#include "application.h"

// ============================================
// =                              Version 0.9
// ============================================


// ============================================
// =                              TO DO
// = Добавить глобальный статус ввода, доступный отовсюду - 
// =    текущее состояние управляющих клавиш и количество бывших нажатий
// ============================================


// Aya goes here
int Application::main(const std::vector<CL_String> &args)
{
	// Текущая версия, для реплеев в основном
	global_state.version = 9;

	// рандомизатор
	srand(CL_System::get_time());
	// Инициализация глобальных переменных
	// Размер рендеригна и игровой области
	global_state.render_size = CL_Sizef(640.0f, 480.0f);
	global_state.game_size = CL_Sizef(384.0f, 448.0f);
	// Размер игровой области и области рендеринга
	global_state.game_field = CL_Rectf(-20, -30, 466, 480);
	global_state.render_field = CL_Rectf(32,16, 416, 464);
	// Общая громкость
	global_state.master_vol = 0.2f;

	// === Загрузка конфигурации ===
	bool is_first_run = true;
	if (ConfigExists())
	{
		LoadConfig();
		is_first_run = false;
	}
	else
	{
		CreateNewConfig();
	}
	global_state.screen_size = global_state.window_size;

	// should be in config
	global_state.is_extra_available = 0;

	// Статус 0 - инициализация
	global_state.game_state = 0;

	// Окна
	// Вспомогательное окно для сохранения контекста OpenGL
	CL_DisplayWindowDescription window_hidden_description;
	window_hidden_description.set_title("_main");
	window_hidden_description.set_size(CL_Size(640, 480), true);
	window_hidden_description.set_visible(false);
	CL_DisplayWindow main_hidden_window = CL_DisplayWindow(window_hidden_description);
	// подключить окно для хранения ресурсов
	_ReconnectGC(main_hidden_window);

	// Текстуры для фреймбуффера
	copy_texture1 = CL_Texture(gc, global_state.render_size.width, global_state.render_size.height);

	// Окно вывода
	win_desc.set_title("Ayaya");
	win_desc.set_size(global_state.screen_size, true);
	CL_DisplayWindow window(win_desc);
	if (!global_state.fullscreen)
		window.hide_cursor();
	// И пересоздать его в соответствии с настройками
	_RecreateWindow(window);

	// Ресурсы
	CL_VirtualFileSystem vfs("ayaya.res", true);
	CL_VirtualDirectory vdir(vfs, "./");
	resources.load("ayaya.xml", vdir);
	graphic_resources.load("sprites.xml", vdir);
	player_resources.load("player.xml", vdir);
//	text_resources.load("text.xml", vdir);
	sound_resources.load("sounds.xml", vdir);
	music_resources.load("music.xml", vdir);
	pattern_resources.load("patterns.xml", vdir);
	level_resources.load("levels.xml", vdir);

	// Паттерны BulletML
	CL_VirtualDirectory tvdir(vfs, "/Patterns");
	CL_VirtualDirectoryListing tvdlist = tvdir.get_directory_listing();
	do
	{
		if (!tvdlist.is_directory())
		{
			cl_log_event("Debug", "Read pattern file %1", tvdlist.get_filename());
			CL_DomDocument tdoc(tvdir.open_file_read(tvdlist.get_filename()));
			bulletml.LoadPatterns(tdoc);
		}
	} while (tvdlist.next());

	// Загрузим сплэш-скрин и покажем его, пока грузим все остальные ресурсы
	splash_screen = new CL_Sprite(gc, "ayaya_splash", &resources);
	_ReconnectGC(window);
	splash_screen->draw(gc, 0, 0);
	window.flip(1);
	CL_KeepAlive::process(0);
	_ReconnectGC(main_hidden_window);

	// Загрузка шрифтов
	//CL_Font sys_font(gc, "tahoma", 16);
	CL_Font_Sprite small_font(gc, "font_small", &resources);
	CL_Font_Sprite score_font(gc, "font_score", &resources);
	CL_Font_Sprite options_font(gc, "font_options", &resources);
	CL_FontDescription rfont;
	rfont.set_typeface_name("Resources\\rf.ttf");
	rfont.set_subpixel(false);
	rfont.set_height(24);
	CL_FontDescription jfont;
	jfont.set_typeface_name("Resources\\jf.ttf");
	jfont.set_subpixel(false);
	jfont.set_height(24);
	CL_Font_Freetype r_font(rfont, vdir);
	CL_Font_Freetype j_font(jfont, vdir);
	CL_FontDescription sfont;
	sfont.set_typeface_name("Resources\\sysf.ttf");
	sfont.set_subpixel(false);
	sfont.set_height(24);
	CL_Font_Freetype sys_font(sfont, vdir);

	// Графика игрового меню и вспомогательных объектов
	screen_mask = new CL_Sprite(gc, "screen_mask", &resources);
	screen_mask->set_scale(global_state.render_size.width, global_state.render_size.height);
	screen_mask->set_linear_filter(false);
	lang_select = new CL_Sprite(gc, "language_select", &resources);
	lang_select->set_frame(0);
	menu_screen = new CL_Sprite(gc, "mm_background", &resources);
	menu_title1 = new CL_Sprite(gc, "mm_title1", &resources);
	menu_list = new CL_Sprite(gc, "mm_menu", &resources);
	menu_list_tips = new CL_Sprite(gc, "mm_menu_tips", &resources);
	menu_options = new CL_Sprite(gc, "om_options", &resources);
	menu_keys = new CL_Sprite(gc, "om_keys", &resources);
	menu_options_tips = new CL_Sprite(gc, "om_tips", &resources);
	game_screen = new CL_Sprite(gc, "game_screen", &resources);
	game_stats = new CL_Sprite(gc, "game_stats", &resources);
	// батчер и объект для рендерера колец
	RingRenderBatcher ring_batcher(gc, "ring_render_program", &resources);
	magic_rings = new RingSprite(gc, &ring_batcher, "ring1", &resources);

	// Загрузка игровой графики
	sprite_container.Load(gc, graphic_resources);

	// Текстура для бэка  концовки
	CL_Texture ending_back_tex(gc, 64, 64);
	ending_back_tex.set_image(CL_ImageProviderFactory::load("Resources\\ending_back.png", vdir));

	// Инициализировать ресурсы диалогов
	dialogs.Init(gc, vdir, get_option_float("dialog_starting_time"), get_option_float("dialog_char_appear_time"), &r_font, &j_font);

	// Звуки
	smanager.Load(sound_resources, music_resources);

	// Игрок
	player.LoadPlayer("player_aya", gc, player_resources);
	//player.AttachInput(window);

	// Рендереры подвижных объектов
	renders.Init(gc, resources);
	// Паттерны
	patterns.Init(global_state.render_field);
	patterns.Load(pattern_resources, vdir);
	
	quit = false;

	// ======= ****** ======

	// объект эффектов босса
	//Background boss_background;

	// Пули
	float bullet_load = 0;
	int bbb_load = 0;
	unsigned int bullet_app_index = 0;
	Bullet new_bullet;

	// Бонусы
	bonus_manager.Init(get_option_float("bonus_accel"), get_option_float("bonus_max_speed"), get_option_float("bonus_score_time"), get_option_float("point_scrore_line"), get_option_int("bonus_point_score_min"), get_option_int("bonus_point_score_max"));

	// ФПС, текущее время и начальные параметры
	FramerateCounter fps_counter;
	unsigned int last_time = CL_System::get_time();

	menu_selection = 0;
	next_menu_selection = 1;
	menu_moving = 0;
	menu_selected = 0;
	menu_finished_work = 0;

	last_joy_x = 0;
	last_joy_y = 0;
	last_pad = -1;
	last_joy_time = (float)CL_System::get_time();
	ResetInputs();

	global_state.game_dialog = 0;
	global_state.game_over = 0;
	global_state.game_paused = 0;
	global_state.game_level_end = 0;
	global_state.game_boss_battle = 0;
	global_state.difficulty = 1; // normal
	global_state.speed_dif = 1; // normal

	float lang_sel_x = global_state.render_size.width / 2 - (float)lang_select->get_width() / 2 - 10;
	float lang_sel_y1 = global_state.render_size.height / 2 - (float)lang_select->get_height() * 1.2f - 10;
	float lang_sel_y2 = global_state.render_size.height / 2 + (float)lang_select->get_height() * 0.2f - 10;
	float lang_sel_w = (float)lang_select->get_width() + 20;
	float lang_sel_h = (float)lang_select->get_height() + 20;
	float sel_y = lang_sel_y1;
	float from_sel_y = lang_sel_y1;
	float next_sel_y = lang_sel_y2;

	EndingMovie ending;

	// ========== Закончили инициализацию и загрузку ===========================
	_ReconnectGC(window);
	
	// Гасим сплэш-скрин
	gc.set_scale(1, 1);
	gc.set_frame_buffer(framebuffer1);
	splash_screen->draw(gc, 0, 0);
	gc.reset_frame_buffer();
	gc.set_translate(global_state.translate.x, global_state.translate.y);
	gc.push_scale(global_state.scale, global_state.scale);
	global_state.time_to_work = 300;
	global_state.time_processed = 0;
	global_state.mask_color = 1;
	delete splash_screen;
	// Статус 1 - плавный переход экрана в какой-то один цвет
	global_state.game_state = 1;
	// Статус 2 - Выбор языка либо главное меню
	if (is_first_run)
		global_state.next_state = 2;
	else
	{
		global_state.next_state = 5;
		global_state.mask_color = 0;
	}
	// Поехали
	cl_log_event("Debug", "Started");
	while (!quit)
	{
		unsigned int current_time = CL_System::get_time();
		int time_difference = current_time - last_time;
		if (time_difference > 17)
			time_difference = 17;		// Ограничить минимальную скорость в 60 кадров
		float time_delta_ms = static_cast<float> (time_difference);
		last_time = current_time;

		// Переключение полноэкранного/оконного режима
		if (keys_fullscreen)
		{
			keys_fullscreen = 0;
			global_state.fullscreen = !global_state.fullscreen;
			_RecreateWindow(window);
		}
		// Изменение размера окна
		if (keys_resize_event)
		{
			keys_resize_event = 0;
			_ResizeWindow(window);
		}

		// Состояние игры
		if (global_state.game_state == 1)
		{
		// Рендерятся переходы между экранами с затуханиями
		// =====================================================
			global_state.time_processed += time_delta_ms;
			if (global_state.time_processed > global_state.time_to_work)
			{
				global_state.game_state = global_state.next_state;
				global_state.time_processed = 0;
				continue;
			}
			gc.clear();
			gc.set_texture(0, copy_texture1);
			CL_Draw::texture(gc, CL_Rectf(0, 0, global_state.render_size.width, global_state.render_size.height));
			screen_mask->set_frame(global_state.mask_color);
			screen_mask->set_alpha(global_state.time_processed / global_state.time_to_work);
			screen_mask->draw(gc, 0, 0);
			gc.reset_texture(0);
		}
		else if (global_state.game_state == 2)
		{
		// =====================================================
		// Меню выбора языка
		// =====================================================
			if (keys_fire)
			{
				// Выбор сделан, инициализировать главное меню и запустить переход в него
				keys_fire = 0;
				global_state.lang = menu_selection;
				menu_selection = 1; // GetFirstMenuOption() ?
				menu_moving = 0;
				menu_after_splash = 1;
				global_state.game_state = 1;
				global_state.next_state = 5; // в главное меню
				global_state.time_to_work = 300;
				global_state.mask_color = 0;
				gc.set_scale(1, 1);
				gc.set_frame_buffer(framebuffer1);
				gc.clear();
				lang_select->set_frame(0);
				lang_select->draw(gc, global_state.render_size.width / 2 - (float)lang_select->get_width() / 2, global_state.render_size.height / 2 - (float)lang_select->get_height() * 1.2f);
				lang_select->set_frame(1);
				lang_select->draw(gc, global_state.render_size.width / 2 - (float)lang_select->get_width() / 2, global_state.render_size.height / 2 + (float)lang_select->get_height() * 0.2f);
				CL_Draw::box(gc, lang_sel_x, sel_y, lang_sel_x+lang_sel_w, sel_y+lang_sel_h, CL_Colorf(0.9f, 0.9f, 1.0f));
				CL_Draw::box(gc, lang_sel_x+1, sel_y+1, lang_sel_x+lang_sel_w-1, sel_y+lang_sel_h-1, CL_Colorf(0.9f, 0.9f, 1.0f, 0.7f));
				CL_Draw::box(gc, lang_sel_x-1, sel_y-1, lang_sel_x+lang_sel_w+1, sel_y+lang_sel_h+1, CL_Colorf(0.9f, 0.9f, 1.0f, 0.7f));
				gc.reset_frame_buffer();
				gc.set_translate(global_state.translate.x, global_state.translate.y);
				gc.push_scale(global_state.scale, global_state.scale);
				continue;
			}
			gc.clear();
			lang_select->set_frame(0);
			lang_select->draw(gc, global_state.render_size.width / 2 - (float)lang_select->get_width() / 2, global_state.render_size.height / 2 - (float)lang_select->get_height() * 1.2f);
			lang_select->set_frame(1);
			lang_select->draw(gc, global_state.render_size.width / 2 - (float)lang_select->get_width() / 2, global_state.render_size.height / 2 + (float)lang_select->get_height() * 0.2f);
			// движение меню
			if (menu_moving)
			{
				global_state.time_processed += time_delta_ms;
				if (global_state.time_processed > 100)
				{
					// закончили движение
					menu_moving = 0;
					global_state.time_processed = 0;
					if (menu_selection)
					{
						// пришли на русский
						menu_selection = 0;
						sel_y = lang_sel_y1;
						from_sel_y = lang_sel_y1;
						next_sel_y = lang_sel_y2;
					}
					else
					{
						// пришли на японский
						menu_selection = 1;
						sel_y = lang_sel_y2;
						from_sel_y = lang_sel_y2;
						next_sel_y = lang_sel_y1;
					}
				}
				else
				{
					sel_y = from_sel_y + (next_sel_y - from_sel_y) * (global_state.time_processed / 100);
				}
			}
			else
			{
				if (keys_up || keys_down)
				{
					keys_up = 0;
					keys_down = 0;
					menu_moving = 1;
				}
			}
			CL_Draw::box(gc, lang_sel_x, sel_y, lang_sel_x+lang_sel_w, sel_y+lang_sel_h, CL_Colorf(0.9f, 0.9f, 1.0f));
			CL_Draw::box(gc, lang_sel_x+1, sel_y+1, lang_sel_x+lang_sel_w-1, sel_y+lang_sel_h-1, CL_Colorf(0.9f, 0.9f, 1.0f, 0.7f));
			CL_Draw::box(gc, lang_sel_x-1, sel_y-1, lang_sel_x+lang_sel_w+1, sel_y+lang_sel_h+1, CL_Colorf(0.9f, 0.9f, 1.0f, 0.7f));
		}
		else if (global_state.game_state == 5)
		{
		// =====================================================
		// Главное меню
		// =====================================================
			if (!global_state.time_processed)
			{
				// Начало работы
				ResetInputs();
				background.load(gc, "background_effects", resources, CL_Rect(global_state.render_size));
				background.set_speed(1);
				for (int i=0; i<100; i++)
					background.scroll(100);
				smanager.PlayMusic("00_kaze_no_shi");
				CheckTimeStart();
			}
			CheckTime("Start point");
			global_state.time_processed += time_delta_ms;
			if (menu_moving)
			// Курсор меню движется между опциями, ввод не воспринимается
			{
				menu_moving += (int) time_delta_ms;
				if (menu_moving > 100)
					menu_moving = 0;
			}
			else if (menu_selected)
			// Меню выбрано, помигать им и перейти в цель выбора
			{
				menu_selected += (int) time_delta_ms;
				if (menu_selected > 500)
				{
					menu_selected = 0;
					menu_finished_work = 1;
				}
			}
			else
			// обработка ввода
			{
				// Выбор меню
				if (keys_fire)
				{
					keys_fire = 0;
					if (menu_selection == 0)
					{
						// Начать игру
						smanager.PlaySound("menu_ok");
						global_state.next_state = 200;
						global_state.player_continues = 3;
						menu_selected = 1;
					}
					if (menu_selection == 1)
					{
						// Replay
						if (replay.LoadReplay("ayaya"))
						{
							smanager.PlaySound("menu_ok");
							global_state.next_state = 300;
							global_state.player_continues = 3;
							menu_selected = 1;
						}
					}
					if (menu_selection == 2)
					{
						// Меню опций
						smanager.PlaySound("menu_ok");
						global_state.next_state = 6;
						menu_selected = 1;
					}
					if (menu_selection == 3)
					{
						// Выход
						quit = true;
					}
				}
				// Движение по меню
				if (keys_up)
				{
					keys_up = 0;
					if (menu_selection == 0)
					{
						menu_selection = 3;
					}
					else if (menu_selection == 1)
					{
						menu_selection = 0;
					}
					else if (menu_selection == 2)
					{
						menu_selection = 1;
					}
					else if (menu_selection == 3)
					{
						menu_selection = 2;
					}
					menu_moving = 1;
					CheckTime("Before sound");
					smanager.PlaySound("menu_select");
					CheckTime("After sound");
				}
				if (keys_down)
				{
					keys_down = 0;
					if (menu_selection == 0)
					{
						menu_selection = 1;
					}
					else if (menu_selection == 1)
					{
						menu_selection = 2;
					}
					else if (menu_selection == 2)
					{
						menu_selection = 3;
					}
					else if (menu_selection == 3)
					{
						menu_selection = 0;
					}
					menu_moving = 1;
					CheckTime("Before sound");
					smanager.PlaySound("menu_select");
					CheckTime("After sound");

				}
				if (keys_cancel && (menu_selection != 3))
				{
					keys_cancel = 0;
					menu_selection = 3;
					menu_moving = 1;
					smanager.PlaySound("menu_cancel");
				}
				if (keys_cancel)
					keys_cancel = 0;
			}
			CheckTime("Menu input processed");
			// Если меню завершило работу, рисуем в буфер всё
			gc.set_scale(1, 1);
			gc.set_frame_buffer(framebuffer1);
			gc.clear();
			// фон
			menu_screen->draw(gc, 0, 0);
			if (!menu_finished_work)
			{
				gc.reset_frame_buffer();
				gc.set_translate(global_state.translate.x, global_state.translate.y);
				gc.push_scale(global_state.scale, global_state.scale);
				gc.set_texture(0, copy_texture1);
				// ---
				CL_Draw::texture(gc, CL_Rectf(0, 0, global_state.render_size.width, global_state.render_size.height));
			}
			CheckTime("Menu background drawn");
			// Снежинки
			background.scroll(time_delta_ms);
			global_state.bg_rect = CL_Rectf(global_state.screen_size);
			background.draw(gc);
			CheckTime("Menu background effects drawn");
			// само меню
			if (global_state.time_processed < 600)
				// меню выезжает справа
				temp_float1 = 740 - sin(CL_Angle(global_state.time_processed * 0.15f, cl_degrees).to_radians()) * 280;
			else
				// уже выехало
				temp_float1 = 460;
			for (int i=0; i< 4; i++)
			{
				if (i == menu_selection)
				{
					menu_list->set_alpha(1.0);
					if (menu_selected)
						// Мигание выбранного пункта меню
						menu_list->set_frame(i*2 + (int)(menu_selected/50)%2);
					else
						menu_list->set_frame(i*2);
				}
				else
				{
					menu_list->set_alpha(0.8f);
					menu_list->set_frame(i*2+1);
				}
				if (menu_moving && (i == menu_selection))
				{
					// движение выбора меню
					temp_float2 = float(600 - menu_moving) / 500;
					menu_list->set_scale(temp_float2, temp_float2);
					menu_list->draw(gc, temp_float1, 270.0f + i*50);
				}
				else
				{
					menu_list->set_scale(1, 1);
					menu_list->draw(gc, temp_float1, 270.0f + i*50);
				}
			}
			CheckTime("Menu drawn");
			// Названия
			if (global_state.time_processed < 300)
				temp_float1 = sin(CL_Angle(global_state.time_processed * 0.3f, cl_degrees).to_radians()) * 300 - 300;
			else
				temp_float1 = 0;
			menu_title1->set_alpha(1.0);
			menu_title1->draw(gc, temp_float1, 0.0f);
			if (global_state.time_processed > 300)
				if (global_state.time_processed < 600)
					temp_float1 = (global_state.time_processed - 300) / 300;
				else
					temp_float1 = 1;
			else
				temp_float1 = 0;
			// Подсказка к главному меню
			menu_list_tips->set_frame(menu_selection * 2 + global_state.lang);
			menu_list_tips->set_alignment(origin_center);
			menu_list_tips->draw(gc, 320, 470);
			// И наложить фильтр, если меню показано после вспышки экрана
			if (menu_after_splash)
			{
				if (global_state.time_processed > 200)
					menu_after_splash = 0; // конец вспышки
				else
				{
					screen_mask->set_frame(global_state.mask_color);
					screen_mask->set_alpha((200 - global_state.time_processed) / 200);
					screen_mask->draw(gc, 0, 0);
				}
			}
			CheckTime("Menu ready");
			// Если меню закончило работу - передаём отрисованную текстуру дальше
			if (menu_finished_work)
			{
				menu_finished_work = 0;
				gc.reset_frame_buffer();
				gc.set_translate(global_state.translate.x, global_state.translate.y);
				gc.push_scale(global_state.scale, global_state.scale);
				gc.set_texture(0, copy_texture1);
				CL_Draw::texture(gc, CL_Rectf(0, 0, global_state.render_size.width, global_state.render_size.height));
				// Начало игры
				if (menu_selection == 0)
				{
					global_state.game_state = 1;
					global_state.next_state = 200;
					global_state.time_to_work = 300;
					global_state.time_processed = 0;
					global_state.mask_color = 1;
					smanager.StopMusic();
				}
				// Переходим в меню реплеев
				if (menu_selection == 1)
				{
					global_state.game_state = 1;
					global_state.next_state = 300;
					global_state.time_to_work = 300;
					global_state.time_processed = 0;
					global_state.mask_color = 11;
					smanager.StopMusic();
				}
				// Переходим в меню опций
				if (menu_selection == 2)
				{
					global_state.game_state = 6;
					global_state.next_state = 7;
					global_state.time_to_work = 300;
					global_state.time_processed = 0;
				}
			}
			// Если рисуем на кривом мониторе, то залить чёрным выступающие края
			FillBorders();
		}
		else if (global_state.game_state == 6)
		{
		// =====================================================
		// Переход из главного меню в меню опций - гашение надписей
		// =====================================================
			global_state.time_processed += time_delta_ms;
			gc.clear();
			temp_float1 = 1.0f - ((global_state.time_processed / global_state.time_to_work) * 0.3f);
			menu_screen->set_alpha(temp_float1);
			menu_screen->draw(gc, 0, 0);
			temp_float1 = (global_state.time_to_work - global_state.time_processed) / global_state.time_to_work;
			menu_title1->set_alpha(temp_float1);
			menu_title1->draw(gc, 0, 0);
			temp_float1 = 900 - cos(CL_Angle(global_state.time_processed * 0.15f, cl_degrees).to_radians()) * 280;
			for (int i=0; i<5; i++)
			{
				if (i == menu_selection)
				{
					menu_list->set_alpha(1.0);
					menu_list->set_frame(i*2);
				}
				else
				{
					menu_list->set_alpha(0.8f);
					menu_list->set_frame(i*2+1);
				}
				menu_list->set_scale(1, 1);
				menu_list->draw(gc, temp_float1, 340.0f + i*50);
			}
			if (global_state.time_processed > global_state.time_to_work)
			{
				global_state.game_state = global_state.next_state;
				global_state.time_processed = 0;
				menu_selection = 0;
				current_menu_selection = global_state.fullscreen;
			}
		}
		else if (global_state.game_state == 7)
		{
		// =====================================================
		// Меню опций
		// =====================================================
			if (!global_state.time_processed)
				ResetInputs();
			global_state.time_processed += time_delta_ms;
			if (menu_moving)
			// Курсор меню движется между опциями, ввод не воспринимается
			{
				menu_moving += (int) time_delta_ms;
				if (menu_moving > 100)
					menu_moving = 0;
			}
			else if (menu_selected)
			// Выбран пункт, переводящий на другой экран или совершающий долгое действие
			// Моргаем пунктом и выполняем действие
			{
				menu_selected += (int) time_delta_ms;
				if (menu_selected > 500)
				{
					// Определяем выбранный пункт
					// 3 - fullscreen
					// 5 - keyconfig
					// 6 - reset
					// 7 - quit
					if (menu_selection == 5)
					{
						menu_selected = 0;
						menu_finished_work = 1;
					}
					if (menu_selection == 6)
					{
						menu_selected = 0;
						current_menu_selection = 0;
						global_state.player_lives = 3;
						global_state.music_volume = 90;
						global_state.sfx_volume = 80;
						global_state.sfx_vol = (float)global_state.sfx_volume / 100.0f;
						global_state.music_vol = (float)global_state.music_volume / 100.0f;
						smanager.UpdateMusicVolume();
					}
					if (menu_selection == 7)
					{
						menu_selected = 0;
						menu_finished_work = 1;
					}
				}
			}
			else
			// обработка ввода
			{
				// Выбор меню
				if (keys_fire)
				{
					keys_fire = 0;
					if (menu_selection == 3)
					{
						if (global_state.fullscreen != !(!current_menu_selection))
						{
							global_state.fullscreen = !(!current_menu_selection);
							_RecreateWindow(window);
						}
						SaveConfig();
					}
					if (menu_selection == 5)
					{
						// Переход в меню переназначения клавиш
						smanager.PlaySound("menu_ok");
						global_state.next_state = 8;
						menu_selected = 1;
					}
					if (menu_selection == 6)
					{
						// Восстановление значений по умолчанию
						smanager.PlaySound("menu_ok");
						menu_selected = 1;
					}
					if (menu_selection == 7)
					{
						// Выход назад в главное меню
						smanager.PlaySound("menu_cancel");
						menu_selected = 1;
						global_state.next_state = 5;
					}
				}
				// Движение по меню
				if (keys_down)
				{
					keys_down = 0;
					menu_selection++;
					if (menu_selection > 7)
						menu_selection = 0;
					menu_moving = 1;
					smanager.PlaySound("menu_select");
				}
				if (keys_up)
				{
					keys_up = 0;
					menu_selection--;
					if (menu_selection < 0)
						menu_selection = 7;
					menu_moving = 1;
					smanager.PlaySound("menu_select");
				}
				if (keys_right)
				{
					keys_right = 0;
					if (menu_selection == 0)
					{
						// выбор количества жизней
						global_state.player_lives++;
						if (global_state.player_lives > 5)
							global_state.player_lives = 5;
						else
							smanager.PlaySound("menu_select");
					}
					if (menu_selection == 1)
					{
						// BGM
						global_state.music_volume +=5;
						if (global_state.music_volume > 100)
							global_state.music_volume = 100;
						else
							smanager.PlaySound("menu_select");
						global_state.music_vol = (float)global_state.music_volume / 100.0f;
						smanager.UpdateMusicVolume();
					}
					if (menu_selection == 2)
					{
						// SFX
						global_state.sfx_volume +=5;
						if (global_state.sfx_volume > 100)
							global_state.sfx_volume = 100;
						else
							smanager.PlaySound("menu_select");
						global_state.sfx_vol = (float)global_state.sfx_volume / 100;
					}
					if (menu_selection == 3)
					{
						// Fullscreen
						if (current_menu_selection)
							smanager.PlaySound("menu_select");
						current_menu_selection = 0;
					}
					if (menu_selection == 4)
					{
						// Language
						if (!global_state.lang)
							smanager.PlaySound("menu_select");
						global_state.lang = 1;
					}
				}
				if (keys_left)
				{
					keys_left = 0;
					if (menu_selection == 0)
					{
						// выбор количества жизней
						global_state.player_lives--;
						if (global_state.player_lives < 1)
							global_state.player_lives = 1;
						else
							smanager.PlaySound("menu_select");
					}
					if (menu_selection == 1)
					{
						// BGM
						global_state.music_volume -=5;
						if (global_state.music_volume < 0)
							global_state.music_volume = 0;
						else
							smanager.PlaySound("menu_select");
						global_state.music_vol = (float)global_state.music_volume / 100.0f;
						smanager.UpdateMusicVolume();
					}
					if (menu_selection == 2)
					{
						// SFX
						global_state.sfx_volume -=5;
						if (global_state.sfx_volume < 0)
							global_state.sfx_volume = 0;
						else
							smanager.PlaySound("menu_select");
						global_state.sfx_vol = (float)global_state.sfx_volume / 100;
					}
					if (menu_selection == 3)
					{
						// Fullscreen
						if (!current_menu_selection)
							smanager.PlaySound("menu_select");
						current_menu_selection = 1;
					}
					if (menu_selection == 4)
					{
						// Language
						if (global_state.lang)
							smanager.PlaySound("menu_select");
						global_state.lang = 0;
					}
				}
				if (keys_cancel && (menu_selection != 7))
				{
					keys_cancel = 0;
					menu_selection = 7;
					menu_moving = 1;
					smanager.PlaySound("menu_cancel");
				}
				if (keys_cancel && (menu_selection == 7))
				{
					// Выход назад в главное меню
					keys_cancel = 0;
					smanager.PlaySound("menu_cancel");
					menu_selected = 1;
					global_state.next_state = 5;
				}
			}
			// Теперь рисуем меню опций
			// фон
			gc.clear();
			menu_screen->set_alpha(0.7f);
			menu_screen->draw(gc, 0, 0);
			if (global_state.time_processed > 300)
			{
				temp_float1 = 1.0f;
				temp_float2 = 1.0f;
			}
			else
			{
				temp_float1 = global_state.time_processed / 300.0f; // alpha
				temp_float2 = 1.0f + sin(CL_Angle(global_state.time_processed * 0.6f, cl_degrees).to_radians()) * 0.3f; // scale
			}
			// Снежинки
			background.scroll(time_delta_ms);
			global_state.bg_rect = CL_Rectf(global_state.screen_size);
			background.draw(gc);
			// Само меню
			for (int i=0; i<8; i++)
			{
				menu_options->set_frame(i);
				if (i == menu_selection)
				{
					if (menu_selected)
					{
						// Мигание выбранного пункта меню
						float varrr = (float)((menu_selected/50)%2) / 2;
						menu_options->set_color(CL_Colorf(0.5f + varrr, 0.5f + varrr, 0.5f + varrr));
						menu_options->set_alpha(0.75f + varrr/2);
					}
					else
					{
						menu_options->set_color(CL_Colorf::white);
						menu_options->set_alpha(1.0);
					}
				}
				else
				{
					menu_options->set_color(CL_Colorf::gray50);
					menu_options->set_alpha(0.75);
				}
				menu_options->set_alpha(menu_options->get_alpha() * temp_float1);
				if (menu_moving && (i == menu_selection))
				{
					// движение выбора меню
					temp_float3 = float(600 - menu_moving) / 500;
					menu_options->set_scale(temp_float3 * temp_float2, temp_float3 * temp_float2);
					menu_options->draw(gc, 60.0f - ((float)(menu_options->get_size().width * temp_float2 - menu_options->get_size().width) * 0.5f), 50.0f + i*45 - ((float)(menu_options->get_size().height * temp_float2 - menu_options->get_size().height) * 0.5f));
				}
				else
				{
					menu_options->set_scale(temp_float2, temp_float2);
					menu_options->draw(gc, 60.0f - ((float)(menu_options->get_size().width * temp_float2 - menu_options->get_size().width) * 0.5f), 50.0f + i*45 - ((float)(menu_options->get_size().height * temp_float2 - menu_options->get_size().height) * 0.5f));
				}
			}
			menu_options->set_scale(temp_float2, temp_float2);
			menu_options->set_alpha(temp_float1);
			// Жизни
			for (int i=1; i<6; i++)
			{
				if (global_state.player_lives == i)
					temp_color = CL_Colorf::white;
				else
					temp_color = CL_Colorf(0.5f, 0.5f, 0.5f, 0.75f);
				temp_color.a = temp_color.a * temp_float1;
				temp_string = cl_format("%1",i);
				options_font.draw_text(gc, 230.0f + i*30 - ((float)(options_font.get_text_size(gc, temp_string).width * temp_float2 - options_font.get_text_size(gc, temp_string).width) * 0.5f), 86.0f - ((float)(options_font.get_text_size(gc, temp_string).height * temp_float2 - options_font.get_text_size(gc, temp_string).height) * 0.5f), temp_float2, temp_float2, temp_string,temp_color);
			}
			temp_color = CL_Colorf::white;
			temp_color.a = temp_color.a * temp_float1;
			// Остальные опции
			if (current_menu_selection) // текущее значение выбора фуллскрина
			{
				menu_options->set_color(CL_Colorf::white);
				menu_options->set_alpha(menu_options->get_alpha() * temp_float1);
				menu_options->set_frame(8);
				menu_options->draw(gc, 260 - ((float)(menu_options->get_size().width * temp_float2 - menu_options->get_size().width) * 0.5f), 185 - ((float)(menu_options->get_size().height * temp_float2 - menu_options->get_size().height) * 0.5f));
				menu_options->set_color(CL_Colorf(0.5f, 0.5f, 0.5f, 0.75f));
				menu_options->set_alpha(menu_options->get_alpha() * temp_float1);
				menu_options->set_frame(9);
				menu_options->draw(gc, 430 - ((float)(menu_options->get_size().width * temp_float2 - menu_options->get_size().width) * 0.5f), 185 - ((float)(menu_options->get_size().height * temp_float2 - menu_options->get_size().height) * 0.5f));
			}
			else
			{
				menu_options->set_color(CL_Colorf(0.5f, 0.5f, 0.5f, 0.75f));
				menu_options->set_alpha(menu_options->get_alpha() * temp_float1);
				menu_options->set_frame(8);
				menu_options->draw(gc, 260 - ((float)(menu_options->get_size().width * temp_float2 - menu_options->get_size().width) * 0.5f), 185 - ((float)(menu_options->get_size().height * temp_float2 - menu_options->get_size().height) * 0.5f));
				menu_options->set_color(CL_Colorf::white);
				menu_options->set_alpha(menu_options->get_alpha() * temp_float1);
				menu_options->set_frame(9);
				menu_options->draw(gc, 430 - ((float)(menu_options->get_size().width * temp_float2 - menu_options->get_size().width) * 0.5f), 185 - ((float)(menu_options->get_size().height * temp_float2 - menu_options->get_size().height) * 0.5f));
			}
			if (global_state.lang) // текущий язык
			{
				menu_options->set_color(CL_Colorf::white);
				menu_options->set_alpha(menu_options->get_alpha() * temp_float1);
				menu_options->set_frame(10);
				menu_options->draw(gc, 430 - ((float)(menu_options->get_size().width * temp_float2 - menu_options->get_size().width) * 0.5f), 230 - ((float)(menu_options->get_size().height * temp_float2 - menu_options->get_size().height) * 0.5f));
				menu_options->set_color(CL_Colorf(0.5f, 0.5f, 0.5f, 0.75f));
				menu_options->set_alpha(menu_options->get_alpha() * temp_float1);
				menu_options->set_frame(11);
				menu_options->draw(gc, 260 - ((float)(menu_options->get_size().width * temp_float2 - menu_options->get_size().width) * 0.5f), 230 - ((float)(menu_options->get_size().height * temp_float2 - menu_options->get_size().height) * 0.5f));
			}
			else
			{
				menu_options->set_color(CL_Colorf(0.5f, 0.5f, 0.5f, 0.75f));
				menu_options->set_alpha(menu_options->get_alpha() * temp_float1);
				menu_options->set_frame(10);
				menu_options->draw(gc, 430 - ((float)(menu_options->get_size().width * temp_float2 - menu_options->get_size().width) * 0.5f), 230 - ((float)(menu_options->get_size().height * temp_float2 - menu_options->get_size().height) * 0.5f));
				menu_options->set_color(CL_Colorf::white);
				menu_options->set_alpha(menu_options->get_alpha() * temp_float1);
				menu_options->set_frame(11);
				menu_options->draw(gc, 260 - ((float)(menu_options->get_size().width * temp_float2 - menu_options->get_size().width) * 0.5f), 230 - ((float)(menu_options->get_size().height * temp_float2 - menu_options->get_size().height) * 0.5f));
			}
			temp_string = cl_format("%1", global_state.music_volume);
			if (temp_string.length() < 2)
				temp_string = CL_String("0") + temp_string;
			temp_string += CL_String("%");
			options_font.draw_text(gc, 260.0f - ((float)(options_font.get_text_size(gc, temp_string).width * temp_float2 - options_font.get_text_size(gc, temp_string).width) * 0.5f), 131.0f - ((float)(options_font.get_text_size(gc, temp_string).height * temp_float2 - options_font.get_text_size(gc, temp_string).height) * 0.5f), temp_float2, temp_float2, temp_string,temp_color);
			temp_string = cl_format("%1", global_state.sfx_volume);
			if (temp_string.length() < 2)
				temp_string = CL_String("0") + temp_string;
			temp_string += CL_String("%");
			options_font.draw_text(gc, 260.0f - ((float)(options_font.get_text_size(gc, temp_string).width * temp_float2 - options_font.get_text_size(gc, temp_string).width) * 0.5f), 176.0f - ((float)(options_font.get_text_size(gc, temp_string).height * temp_float2 - options_font.get_text_size(gc, temp_string).height) * 0.5f), temp_float2, temp_float2, temp_string,temp_color);
			// Подсказка к меню опций
			menu_options_tips->set_frame(menu_selection * 2 + global_state.lang);
			menu_options_tips->set_alignment(origin_center);
			menu_options_tips->draw(gc, 320, 470);
			// Если меню закончило работу - возвращаемся в главное или переходим в настройки кнопок
			if (menu_finished_work)
			{
				menu_finished_work = 0;
				if (global_state.fullscreen != !(!current_menu_selection))
				{
					global_state.fullscreen = !(!current_menu_selection);
					_RecreateWindow(window);
				}
				SaveConfig();
				// Переходим в настройки пада
				if (menu_selection == 5)
				{
					global_state.game_state = 9;
					global_state.next_state = 9;
					global_state.time_to_work = 300;
					global_state.time_processed = 0;
					menu_selection = 0;
					menu_moving = 0;
				}
				// Выходим в меню опций
				if (menu_selection == 7)
				{
					global_state.game_state = 5;
					global_state.next_state = 5;
					global_state.time_to_work = 300;
					global_state.time_processed = 1;
					menu_selection = 2;
					menu_moving = 0;
					menu_after_splash = 0;
					menu_screen->set_alpha(1.0);
					ResetInputs();
				}
			}
			// Если рисуем на кривом мониторе, то залить чёрным выступающие края
			FillBorders();
		}
		else if (global_state.game_state == 9)
		{
		// =====================================================
		// Меню настроек геймпада
		// =====================================================
			if (!global_state.time_processed)
				ResetInputs();
			global_state.time_processed += time_delta_ms;
			if (menu_moving)
			// Курсор меню движется между опциями, ввод не воспринимается
			{
				menu_moving += (int) time_delta_ms;
				if (menu_moving > 100)
					menu_moving = 0;
			}
			else if (menu_selected)
			// Выбран пункт, переводящий на другой экран или совершающий долгое действие
			// Моргаем пунктом и выполняем действие
			{
				menu_selected += (int) time_delta_ms;
				if (menu_selected > 500)
				{
					// Определяем выбранный пункт
					// 7 - reset
					// 8 - quit
					if (menu_selection == 7)
					{
						menu_selected = 0;
						global_state.axis_sens = 0.5;
						global_state.key_fire = 1;
						global_state.key_bomb = 0;
						global_state.key_focus = 5;
						global_state.key_spell = 2; // здесь будет непрерывный выстрел
						global_state.key_pause = 7;
						global_state.shotslow = 0;
					}
					if (menu_selection == 8)
					{
						menu_selected = 0;
						menu_finished_work = 1;
					}
				}
			}
			else
			// обработка ввода
			{
				// Переустановка кнопок
				if (keys_joy)
				{
					// Смена конфигурации кнопок
					int key = keys_joy - 1;
					keys_joy = 0;
					if (menu_selection < 5)
						ResetInputs();
					if (menu_selection == 0)
					{
						if (global_state.key_fire != key)
						{
							ReplaceKey(key, global_state.key_fire);
							global_state.key_fire = key;
						}
					}
					if (menu_selection == 1)
					{
						if (global_state.key_bomb != key)
						{
							ReplaceKey(key, global_state.key_bomb);
							global_state.key_bomb = key;
						}
					}
					if (menu_selection == 2)
					{
						if (global_state.key_focus != key)
						{
							ReplaceKey(key, global_state.key_focus);
							global_state.key_focus = key;
						}
					}
					if (menu_selection == 3)
					{
						if (global_state.key_spell != key)
						{
							ReplaceKey(key, global_state.key_spell);
							global_state.key_spell = key;
						}
					}
					if (menu_selection == 4)
					{
						if (global_state.key_pause != key)
						{
							ReplaceKey(key, global_state.key_pause);
							global_state.key_pause = key;
						}
					}
				}
				// Выбор меню
				if (keys_fire)
				{
					keys_fire = 0;
					if (menu_selection == 7)
					{
						// Восстановление значений по умолчанию
						smanager.PlaySound("menu_ok");
						menu_selected = 1;
					}
					if (menu_selection == 8)
					{
						// Выход назад в меню опций
						smanager.PlaySound("menu_cancel");
						menu_selected = 1;
						global_state.next_state = 7;
					}
				}
				// Движение по меню
				if (keys_down)
				{
					keys_down = 0;
					menu_selection++;
					if (menu_selection > 8)
						menu_selection = 0;
					menu_moving = 1;
					smanager.PlaySound("menu_select");
				}
				if (keys_up)
				{
					keys_up = 0;
					menu_selection--;
					if (menu_selection < 0)
						menu_selection = 8;
					menu_moving = 1;
					smanager.PlaySound("menu_select");
				}
				if (keys_right)
				{
					keys_right = 0;
					if (menu_selection == 5)
					{
						// Чувствительность стика
						global_state.axis_sens += 0.01f;
						if (global_state.axis_sens > 1.0f)
							global_state.axis_sens = 1.0f;
					}
					if (menu_selection == 6)
					{
						// Shot Slow
						if (!global_state.shotslow)
							smanager.PlaySound("menu_select");
						global_state.shotslow = 1;
					}
				}
				if (keys_left)
				{
					keys_left = 0;
					if (menu_selection == 5)
					{
						// Чувствительность стика
						global_state.axis_sens -= 0.01f;
						if (global_state.axis_sens < 0.01f)
							global_state.axis_sens = 0.01f;
					}
					if (menu_selection == 6)
					{
						// Shot Slow
						if (global_state.shotslow)
							smanager.PlaySound("menu_select");
						global_state.shotslow = 0;
					}
				}
				if (keys_cancel && (menu_selection != 8))
				{
					keys_cancel = 0;
					menu_selection = 8;
					menu_moving = 1;
					smanager.PlaySound("menu_cancel");
				}
				if (keys_cancel && (menu_selection == 8))
				{
					// Выход назад в меню опций
					keys_cancel = 0;
					smanager.PlaySound("menu_cancel");
					menu_selected = 1;
					global_state.next_state = 7;
				}
			}
			// Теперь рисуем меню кнопок
			// фон
			gc.clear();
			menu_screen->set_alpha(0.7f);
			menu_screen->draw(gc, 0, 0);
			if (global_state.time_processed > 300)
			{
				temp_float1 = 1.0f;
				temp_float2 = 1.0f;
			}
			else
			{
				temp_float1 = global_state.time_processed / 300.0f; // alpha
				temp_float2 = 1.0f + sin(CL_Angle(global_state.time_processed * 0.6f, cl_degrees).to_radians()) * 0.3f; // scale
			}
			// Снежинки
			background.scroll(time_delta_ms);
			global_state.bg_rect = CL_Rectf(global_state.screen_size);
			background.draw(gc);
			// Само меню
			for (int i=0; i<9; i++)
			{
				menu_keys->set_frame(i);
				if (i == menu_selection)
				{
					if (menu_selected)
					{
						// Мигание выбранного пункта меню
						float varrr = (float)((menu_selected/50)%2) / 2;
						menu_keys->set_color(CL_Colorf(0.5f + varrr, 0.5f + varrr, 0.5f + varrr));
						menu_keys->set_alpha(0.75f + varrr/2);
					}
					else
					{
						menu_keys->set_color(CL_Colorf::white);
						menu_keys->set_alpha(1.0);
					}
				}
				else
				{
					menu_keys->set_color(CL_Colorf::gray50);
					menu_keys->set_alpha(0.75);
				}
				menu_keys->set_alpha(menu_keys->get_alpha() * temp_float1);
				if (menu_moving && (i == menu_selection))
				{
					// движение выбора меню
					temp_float3 = float(600 - menu_moving) / 500;
					menu_keys->set_scale(temp_float3 * temp_float2, temp_float3 * temp_float2);
					menu_keys->draw(gc, 60.0f - ((float)(menu_keys->get_size().width * temp_float2 - menu_keys->get_size().width) * 0.5f), 20.0f + i*45 - ((float)(menu_keys->get_size().height * temp_float2 - menu_keys->get_size().height) * 0.5f));
				}
				else
				{
					menu_keys->set_scale(temp_float2, temp_float2);
					menu_keys->draw(gc, 60.0f - ((float)(menu_keys->get_size().width * temp_float2 - menu_keys->get_size().width) * 0.5f), 20.0f + i*45 - ((float)(menu_keys->get_size().height * temp_float2 - menu_keys->get_size().height) * 0.5f));
				}
			}
			menu_keys->set_scale(temp_float2, temp_float2);
			menu_keys->set_alpha(temp_float1);
			temp_color = CL_Colorf::white;
			temp_color.a = temp_color.a * temp_float1;
			// Кнопки
			// Fire
			temp_string = cl_format("%1", global_state.key_fire);
			if (temp_string.length() < 2)
				temp_string = CL_String("0") + temp_string;
			options_font.draw_text(gc, 260.0f - ((float)(options_font.get_text_size(gc, temp_string).width * temp_float2 - options_font.get_text_size(gc, temp_string).width) * 0.5f), 56.0f - ((float)(options_font.get_text_size(gc, temp_string).height * temp_float2 - options_font.get_text_size(gc, temp_string).height) * 0.5f), temp_float2, temp_float2, temp_string,temp_color);
			// Bomb
			temp_string = cl_format("%1", global_state.key_bomb);
			if (temp_string.length() < 2)
				temp_string = CL_String("0") + temp_string;
			options_font.draw_text(gc, 260.0f - ((float)(options_font.get_text_size(gc, temp_string).width * temp_float2 - options_font.get_text_size(gc, temp_string).width) * 0.5f), 101.0f - ((float)(options_font.get_text_size(gc, temp_string).height * temp_float2 - options_font.get_text_size(gc, temp_string).height) * 0.5f), temp_float2, temp_float2, temp_string,temp_color);
			// Focus
			temp_string = cl_format("%1", global_state.key_focus);
			if (temp_string.length() < 2)
				temp_string = CL_String("0") + temp_string;
			options_font.draw_text(gc, 260.0f - ((float)(options_font.get_text_size(gc, temp_string).width * temp_float2 - options_font.get_text_size(gc, temp_string).width) * 0.5f), 146.0f - ((float)(options_font.get_text_size(gc, temp_string).height * temp_float2 - options_font.get_text_size(gc, temp_string).height) * 0.5f), temp_float2, temp_float2, temp_string,temp_color);
			// Rapid fire
			temp_string = cl_format("%1", global_state.key_spell);
			if (temp_string.length() < 2)
				temp_string = CL_String("0") + temp_string;
			options_font.draw_text(gc, 260.0f - ((float)(options_font.get_text_size(gc, temp_string).width * temp_float2 - options_font.get_text_size(gc, temp_string).width) * 0.5f), 191.0f - ((float)(options_font.get_text_size(gc, temp_string).height * temp_float2 - options_font.get_text_size(gc, temp_string).height) * 0.5f), temp_float2, temp_float2, temp_string,temp_color);
			// Pause
			temp_string = cl_format("%1", global_state.key_pause);
			if (temp_string.length() < 2)
				temp_string = CL_String("0") + temp_string;
			options_font.draw_text(gc, 260.0f - ((float)(options_font.get_text_size(gc, temp_string).width * temp_float2 - options_font.get_text_size(gc, temp_string).width) * 0.5f), 236.0f - ((float)(options_font.get_text_size(gc, temp_string).height * temp_float2 - options_font.get_text_size(gc, temp_string).height) * 0.5f), temp_float2, temp_float2, temp_string,temp_color);
			// Чувствительность стика
			temp_string = cl_format("%1", (int)(global_state.axis_sens * 100));
			options_font.draw_text(gc, 260.0f - ((float)(options_font.get_text_size(gc, temp_string).width * temp_float2 - options_font.get_text_size(gc, temp_string).width) * 0.5f), 281.0f - ((float)(options_font.get_text_size(gc, temp_string).height * temp_float2 - options_font.get_text_size(gc, temp_string).height) * 0.5f), temp_float2, temp_float2, temp_string,temp_color);
			// Замедление при выстерле
			if (!global_state.shotslow)
			{
				menu_keys->set_color(CL_Colorf::white);
				menu_keys->set_frame(9);
				menu_keys->draw(gc, 260 - ((float)(menu_keys->get_size().width * temp_float2 - menu_keys->get_size().width) * 0.5f), 290 - ((float)(menu_keys->get_size().height * temp_float2 - menu_keys->get_size().height) * 0.5f));
				menu_keys->set_color(CL_Colorf(0.5f, 0.5f, 0.5f, 0.75f));
				menu_keys->set_frame(10);
				menu_keys->draw(gc, 330 - ((float)(menu_keys->get_size().width * temp_float2 - menu_keys->get_size().width) * 0.5f), 290 - ((float)(menu_keys->get_size().height * temp_float2 - menu_keys->get_size().height) * 0.5f));
			}
			else
			{
				menu_keys->set_color(CL_Colorf(0.5f, 0.5f, 0.5f, 0.75f));
				menu_keys->set_frame(9);
				menu_keys->draw(gc, 260 - ((float)(menu_keys->get_size().width * temp_float2 - menu_keys->get_size().width) * 0.5f), 290 - ((float)(menu_keys->get_size().height * temp_float2 - menu_keys->get_size().height) * 0.5f));
				menu_keys->set_color(CL_Colorf::white);
				menu_keys->set_frame(10);
				menu_keys->draw(gc, 330 - ((float)(menu_keys->get_size().width * temp_float2 - menu_keys->get_size().width) * 0.5f), 290 - ((float)(menu_keys->get_size().height * temp_float2 - menu_keys->get_size().height) * 0.5f));
			}
			// Подсказка к меню кнопок
			menu_options_tips->set_frame((menu_selection + 8) * 2 + global_state.lang);
			menu_options_tips->set_alignment(origin_center);
			menu_options_tips->draw(gc, 320, 470);
			// Если меню закончило работу - возвращаемся в меню опций
			if (menu_finished_work)
			{
				menu_finished_work = 0;
				SaveConfig();
				// Выходим в меню опций
				if (menu_selection == 8)
				{
					global_state.game_state = 7;
					global_state.next_state = 7;
					global_state.time_to_work = 300;
					global_state.time_processed = 0;
					menu_selection = 0;
					menu_moving = 0;
				}
			}
			// Если рисуем на кривом мониторе, то залить чёрным выступающие края
			FillBorders();
		}
		else if (global_state.game_state == 100)
		{
		// =====================================================
		// Цикл активной игры
		// =====================================================
		}
		else if (global_state.game_state == 200)
		{
		// =====================================================
		// Практика
		// =====================================================
			// Начальные установки
			if (global_state.time_processed == 0)
			{
				global_state.game_paused = 0;
				global_state.game_dialog = 0;
				global_state.game_over = 0;
				global_state.game_level_end = 0;
				global_state.game_boss_battle = 0;
				global_state.game_boss_spellcard_active = 0;
				global_state.time_collected = 0;
				global_state.bullets_launched = 0;
				global_state.bullets_blowed = 0;
				player.Reset();
				player.lives = global_state.player_lives - 1; // В игре считаются лишние жизни сверх той, что есть
				player.invicible = player.invicible_time;
				player.wind = 100.0f;
				player.is_bomb = false;
				player.wind_trigger = false;
				player.wind_activated = false;
				player.position = CL_Vec2<float>(255,550);
				player.prev_position = CL_Vec2<float>(255,550);
				// Загрузим уровень
				_ReconnectGC(main_hidden_window);
				background.load(gc, "stage_aya", resources, (CL_Rect) global_state.render_field);
				boss_background.load(gc, "boss_effects", resources, (CL_Rect) global_state.render_field);
				_ReconnectGC(window);
				// И проскроллим его немного, чтобы эффекты наполнили экран
				for (int i=0; i<100; i++)
					background.scroll(1000);
				background.set_speed(1);
				boss_background.set_speed(1);
				global_state.time_processed = 1;
				// Загрузим тестовый уровень
				game_timer.Load(level_resources, "testlevel");
				// Обнулим все хранилища объектов
				patterns.Clear();
				bmanager.Clear();
				emanager.Clear();
				effects.Clear();
				bonus_manager.Clear();
				ResetInputs();

				replay.ClearReplay();
			}

			// Проверим паузу
			if (keys_cancel)
			{
				keys_cancel = 0;
				global_state.game_paused = 1;
			}

			if (global_state.game_dialog)
			{
				// Апдейтнуть течение диалога
				dialogs.UpdateDialog(time_delta_ms, keys_fire);
				// Выставить флаг в реплей, если диалог листается
				if (keys_fire)
					replay.SetKeysPressed();
				keys_fire = 0;
				// вывести диалоги в конце, после отрисовки всего остального
			}
			else
			{
				// обычное течение уровня
				global_state.time_processed += time_delta_ms;
				keys_fire = 0;
			}
			
			//   Работа скрипта уровня
			if (!global_state.game_dialog && !global_state.game_over && !global_state.game_paused && !global_state.game_level_end && !global_state.game_boss_battle)
			{
				game_timer.Process(time_delta_ms);
			}
			// Не умер ли игрок
			if (player.dead)
			{
				if (!player.dead_time)
				{
					// Смерть только что сработала
					player.lives--;
					player.invicible = player.invicible_time;
					player.wind = 100.0f;
					// Ополовинить силу и выкинуть бонусы
					player.DropBonus();
				}
				if (player.dead_time > player.death_time)
				{
					// Прошёл интервал обработки анимации смерти, можно действовать дальше
					if (player.lives < 0)
					{
						// гамовер
						player.lives = 0;
						global_state.game_over = 1;
					}
					else
					{
						if (player.dead_time > (player.death_time * 2))
						{
							// даём игроку управление
							player.dead = false;
							// И уничтожаем всех врагов на экране
							GameObject canceler;
							canceler.position = player.position;
							canceler.prev_position = player.position;
							canceler.collision_size = global_state.game_size.height * 2;
							emanager.DestroyEnemies(&canceler);
						}
						else
						{
							// выдвигаем игрока и стираем пули
							// подаём нового игрока снизу
							// === TO DO ===
							// Сделать плавный выезд снизу экрана
							// Стираем пули
							GameObject canceler;
							canceler.position = player.position;
							canceler.prev_position = player.position;
							canceler.collision_size = ((player.dead_time - player.death_time) / player.death_time) * global_state.game_size.height;
							bmanager.CancelBullets(&canceler);
						}
					}
				}
			}
			// Если включается экран паузы/продолжения/статистики, отрендерить в текстуру
			if (global_state.game_over || global_state.game_paused || global_state.game_level_end)
			{
				gc.set_scale(1, 1);
				gc.set_frame_buffer(framebuffer1);
				global_state.clip_rect = global_state.render_field;
			}
			// Основной цикл
			// Двигаем фон
			background.scroll(time_delta_ms);
			// Двигаем эффекты фона
			// - бомбы, затемнения и т.д.
			// ---
			// ---
			// ==============================================
			// =   Прибавляем игровое время, рассчитываем глобальные события
			// ==============================================
			// Двигаем всех врагов
			emanager.Update(time_delta_ms);
			// Апдейтим игрока
			player.Update(time_delta_ms);
			// Сохраняем данные реплея
			replay.AddFrame(time_delta_ms);
			// ---
			// Двигаем бонусы
			bonus_manager.Update(time_delta_ms);
			// Обрабатываем паттерны
			patterns.Update(time_delta_ms);
			// Двигаем пули
			bmanager.Update(time_delta_ms);
			// Грейзим пули
			bmanager.GrazeBullets(time_delta_ms);
			// Анимируем эффекты
			effects.Update(time_delta_ms);
			// Просчитываем все столкновения
			// - игрока с пулями и противниками
			if (!player.dead && !global_state.game_dialog)
				player.CalculateCollisions();
			// - игрока с бонусами
			if (!player.dead)
				bonus_manager.CalculateCollisions();
			// - противников с пулями игрока
			if (!global_state.game_dialog)
				emanager.CalculateCollisions();
			// После чего обновляем анимацию мёртвых объектов
			//bmanager.UpdateDead(time_delta_ms);
			emanager.UpdateDead(time_delta_ms);
			// ==============================================
			// Теперь всё это рисуем
			// ==============================================
			gc.clear();
			// фон-рамку
			game_screen->draw(gc, 0, 0);
			//gc.clear(CL_Colorf(0.0f,0.0f,0.2f));
			// игровой фон
			global_state.bg_rect = global_state.clip_rect;
			background.draw(gc);
			// Фон босса
			if (global_state.game_boss_battle)
			{
				DrawBossBackground(time_delta_ms);
			}
			//magic_rings->set_frame(0);
			//magic_rings->draw_ring(gc, 250.f, 300.f, 150.f, 30.f, 0);
			//magic_rings->set_frame(1);
			//magic_rings->draw_ring(gc, 250.f, 300.f, 200.f, 30.f, 0);
			// Фон игрока
			player.RenderBack(gc, magic_rings);
			// остаточные анимации мёртвых пуль и врагов
			emanager.RenderDead(gc, (CL_Rect) global_state.clip_rect);
			// ---
			// противников
			emanager.Render(gc, (CL_Rect) global_state.clip_rect);
			// пули игрока
			bmanager.Render(gc, (CL_Rect) global_state.clip_rect, 0);
			// игрока
			player.Render(gc);
			// эффекты
			effects.Render(gc, (CL_Rect) global_state.clip_rect);
			// бонусы
			bonus_manager.Render(gc, (CL_Rect) global_state.clip_rect);
			// пули противников
			bmanager.Render(gc, (CL_Rect) global_state.clip_rect, 1);
			// И обновляем статистическую информацию
			if (global_state.game_boss_battle)
			{
				// Статистика босса
				DrawBossStats(score_font);
			}
			DrawStats(score_font);
			// ==============================================
			// Теперь поверх всего рисуем диалоги
			if (global_state.game_dialog)
			{
				dialogs.RenderDialog(gc);
			}
			// Конец игры либо пауза
			if (global_state.game_over || global_state.game_paused)
			{
				gc.reset_frame_buffer();
				gc.set_translate(global_state.translate.x, global_state.translate.y);
				gc.push_scale(global_state.scale, global_state.scale);
				global_state.clip_rect = CL_Rectf(global_state.render_field.left * global_state.scale, global_state.render_field.top * global_state.scale, global_state.render_field.right * global_state.scale, global_state.render_field.bottom * global_state.scale);
				global_state.clip_rect.translate(global_state.translate);
				gc.set_texture(0, copy_texture1);
				CL_Draw::texture(gc, CL_Rectf(0, 0, global_state.render_size.width, global_state.render_size.height));
				gc.reset_texture(0);
				global_state.game_state = 1001; // Переходим в экран паузы
				global_state.next_state = 200; // После которого возвращаемся сюда
				global_state.time_paused = 0;
				ResetInputs();
			}
			// Конец уровня и переход на экран статистики
			if (global_state.game_level_end)
			{
				gc.reset_frame_buffer();
				gc.set_translate(global_state.translate.x, global_state.translate.y);
				gc.push_scale(global_state.scale, global_state.scale);
				global_state.clip_rect = CL_Rectf(global_state.render_field.left * global_state.scale, global_state.render_field.top * global_state.scale, global_state.render_field.right * global_state.scale, global_state.render_field.bottom * global_state.scale);
				global_state.clip_rect.translate(global_state.translate);
				gc.set_texture(0, copy_texture1);
				CL_Draw::texture(gc, CL_Rectf(0, 0, global_state.render_size.width, global_state.render_size.height));
				gc.reset_texture(0);
				global_state.game_state = 1500; // Переходим в экран статистики
				global_state.time_paused = 0;
				ResetInputs();
				// test replay
				replay.SaveReplay("ayaya");
			}
			// Если рисуем на кривом мониторе, то залить чёрным выступающие края
			FillBorders();
		}
		else if (global_state.game_state == 300)
		{
		// =====================================================
		// Реплей
		// =====================================================
			// Начальные установки
			if (global_state.time_processed == 0)
			{
				global_state.game_paused = 0;
				global_state.game_dialog = 0;
				global_state.game_over = 0;
				global_state.game_level_end = 0;
				global_state.game_boss_battle = 0;
				global_state.game_boss_spellcard_active = 0;
				global_state.time_collected = 0;
				global_state.bullets_launched = 0;
				global_state.bullets_blowed = 0;
				player.Reset();
				player.lives = global_state.player_lives - 1; // В игре считаются лишние жизни сверх той, что есть
				player.invicible = player.invicible_time;
				player.wind = 100.0f;
				player.is_bomb = false;
				player.wind_trigger = false;
				player.wind_activated = false;
				player.position = CL_Vec2<float>(255,550);
				player.prev_position = CL_Vec2<float>(255,550);
				// Загрузим уровень
				_ReconnectGC(main_hidden_window);
				background.load(gc, "stage_aya", resources, (CL_Rect) global_state.render_field);
				boss_background.load(gc, "boss_effects", resources, (CL_Rect) global_state.render_field);
				_ReconnectGC(window);
				background.set_speed(1);
				boss_background.set_speed(1);
				// И проскроллим его немного, чтобы эффекты наполнили экран
				for (int i=0; i<100; i++)
					background.scroll(1000);
				global_state.time_processed = 1;
				// Загрузим тестовый уровень
				game_timer.Load(level_resources, "testlevel");
				// Обнулим все хранилища объектов
				patterns.Clear();
				bmanager.Clear();
				emanager.Clear();
				effects.Clear();
				bonus_manager.Clear();
				ResetInputs();

				replay.ResetReplay();
			}
			// Получить время фрейма
			time_delta_ms = replay.GetFrameData().time;

			// Проверим паузу
			if (keys_cancel)
			{
				keys_cancel = 0;
				global_state.game_paused = 1;
			}

			if (global_state.game_dialog)
			{
				// Апдейтнуть течение диалога
				dialogs.UpdateDialog(time_delta_ms, replay.GetFrameData().player_keys);
				// вывести диалоги в конце, после отрисовки всего остального
			}
			else
			{
				// обычное течение уровня
				global_state.time_processed += time_delta_ms;
			}
			
			//   Работа скрипта уровня
			if (!global_state.game_dialog && !global_state.game_over && !global_state.game_paused && !global_state.game_level_end && !global_state.game_boss_battle)
			{
				game_timer.Process(time_delta_ms);
			}
			// Не умер ли игрок
			if (player.dead)
			{
				if (!player.dead_time)
				{
					// Смерть только что сработала
					player.lives--;
					//player.Reset();
					player.invicible = player.invicible_time;
					player.wind = 100.0f;
					// Ополовинить силу и выкинуть бонусы
					player.DropBonus();
				}
				if (player.dead_time > player.death_time)
				{
					// Прошёл интервал обработки анимации смерти, можно действовать дальше
					if (player.lives < 0)
					{
						// гамовер
						player.lives = 0;
						global_state.game_over = 1;
					}
					else
					{
						if (player.dead_time > (player.death_time * 2))
						{
							// даём игроку управление
							player.dead = false;
							// И уничтожаем всех врагов на экране
							GameObject canceler;
							canceler.position = player.position;
							canceler.prev_position = player.position;
							canceler.collision_size = global_state.game_size.height * 2;
							emanager.DestroyEnemies(&canceler);
						}
						else
						{
							// выдвигаем игрока и стираем пули
							// подаём нового игрока снизу
							// === TO DO ===
							// Сделать плавный выезд снизу экрана
							// Стираем пули
							GameObject canceler;
							canceler.position = player.position;
							canceler.prev_position = player.position;
							canceler.collision_size = ((player.dead_time - player.death_time) / player.death_time) * global_state.game_size.height;
							bmanager.CancelBullets(&canceler);
						}
					}
				}
			}
			// Если включается экран паузы/продолжения/статистики, отрендерить в текстуру
			if (global_state.game_over || global_state.game_paused || global_state.game_level_end)
			{
				gc.set_scale(1, 1);
				gc.set_frame_buffer(framebuffer1);
				global_state.clip_rect = global_state.render_field;
			}
			// Основной цикл
			// Двигаем фон
			background.scroll(time_delta_ms);
			// Двигаем эффекты фона
			// - бомбы, затемнения и т.д.
			// ---
			// ---
			// ==============================================
			// =   Прибавляем игровое время, рассчитываем глобальные события
			// ==============================================
			// Двигаем всех врагов
			emanager.Update(time_delta_ms);
			// Апдейтим из данных реплея
			player.UpdateFromReplay(replay.GetFrameData());
			// ---
			// Двигаем бонусы
			bonus_manager.Update(time_delta_ms);
			// Обрабатываем паттерны
			patterns.Update(time_delta_ms);
			// Двигаем пули
			bmanager.Update(time_delta_ms);
			// Грейзим пули
			bmanager.GrazeBullets(time_delta_ms);
			// Анимируем эффекты
			effects.Update(time_delta_ms);
			// Просчитываем все столкновения
			// - игрока с пулями и противниками
			if (!player.dead && !global_state.game_dialog)
				player.CalculateCollisions();
			// - игрока с бонусами
			if (!player.dead)
				bonus_manager.CalculateCollisions();
			// - противников с пулями игрока
			if (!global_state.game_dialog)
				emanager.CalculateCollisions();
			// После чего обновляем анимацию мёртвых объектов
			//bmanager.UpdateDead(time_delta_ms);
			emanager.UpdateDead(time_delta_ms);
			// ==============================================
			// Теперь всё это рисуем
			// ==============================================
			gc.clear();
			// фон-рамку
			game_screen->draw(gc, 0, 0);
			//gc.clear(CL_Colorf(0.0f,0.0f,0.2f));
			// игровой фон
			global_state.bg_rect = global_state.clip_rect;
			background.draw(gc);
			// Фон босса
			if (global_state.game_boss_battle)
			{
				DrawBossBackground(time_delta_ms);
			}
			// Фон игрока
			player.RenderBack(gc, magic_rings);
			// остаточные анимации мёртвых пуль и врагов
			emanager.RenderDead(gc, (CL_Rect) global_state.clip_rect);
			// ---
			// противников
			emanager.Render(gc, (CL_Rect) global_state.clip_rect);
			// пули игрока
			bmanager.Render(gc, (CL_Rect) global_state.clip_rect, 0);
			// игрока
			player.Render(gc);
			// эффекты
			effects.Render(gc, (CL_Rect) global_state.clip_rect);
			// бонусы
			bonus_manager.Render(gc, (CL_Rect) global_state.clip_rect);
			// пули противников
			bmanager.Render(gc, (CL_Rect) global_state.clip_rect, 1);
			// И обновляем статистическую информацию
			if (global_state.game_boss_battle)
			{
				// Статистика босса
				DrawBossStats(score_font);
			}
			DrawStats(score_font);
			// ==============================================
			// Теперь поверх всего рисуем диалоги
			if (global_state.game_dialog)
			{
				dialogs.RenderDialog(gc);
			}
			// Берём следующий кадр реплея
			if (!replay.NextFrame())
			{
				global_state.game_over = 1; // Закончились кадры
			}
			// Пауза
			if (global_state.game_paused)
			{
				gc.reset_frame_buffer();
				gc.set_translate(global_state.translate.x, global_state.translate.y);
				gc.push_scale(global_state.scale, global_state.scale);
				global_state.clip_rect = CL_Rectf(global_state.render_field.left * global_state.scale, global_state.render_field.top * global_state.scale, global_state.render_field.right * global_state.scale, global_state.render_field.bottom * global_state.scale);
				global_state.clip_rect.translate(global_state.translate);
				gc.set_texture(0, copy_texture1);
				CL_Draw::texture(gc, CL_Rectf(0, 0, global_state.render_size.width, global_state.render_size.height));
				gc.reset_texture(0);
				global_state.game_state = 1001; // Переходим в экран паузы
				global_state.next_state = 300; // После которого возвращаемся сюда
				global_state.time_paused = 0;
				ResetInputs();
			}
			// Конец реплея
			if (global_state.game_over)
			{
				UnloadLevel();
				menu_selection = 0;
				gc.reset_frame_buffer();
				gc.set_translate(global_state.translate.x, global_state.translate.y);
				gc.push_scale(global_state.scale, global_state.scale);
				global_state.clip_rect = CL_Rectf(global_state.render_field.left * global_state.scale, global_state.render_field.top * global_state.scale, global_state.render_field.right * global_state.scale, global_state.render_field.bottom * global_state.scale);
				global_state.clip_rect.translate(global_state.translate);
				gc.set_texture(0, copy_texture1);
				CL_Draw::texture(gc, CL_Rectf(0, 0, global_state.render_size.width, global_state.render_size.height));
				gc.reset_texture(0);
				global_state.game_state = 5; // Выходим в меню
				global_state.next_state = 5; // После которого возвращаемся сюда
				global_state.time_paused = 0;
				ResetInputs();
			}
			// Конец уровня и выход в меню реплеев (пока в главное)
			if (global_state.game_level_end)
			{
				UnloadLevel();
				menu_selection = 0;
				gc.reset_frame_buffer();
				gc.set_translate(global_state.translate.x, global_state.translate.y);
				gc.push_scale(global_state.scale, global_state.scale);
				global_state.clip_rect = CL_Rectf(global_state.render_field.left * global_state.scale, global_state.render_field.top * global_state.scale, global_state.render_field.right * global_state.scale, global_state.render_field.bottom * global_state.scale);
				global_state.clip_rect.translate(global_state.translate);
				gc.set_texture(0, copy_texture1);
				CL_Draw::texture(gc, CL_Rectf(0, 0, global_state.render_size.width, global_state.render_size.height));
				gc.reset_texture(0);
				global_state.game_state = 5; // Переходим в меню
				global_state.next_state = 5;
				global_state.time_paused = 0;
				ResetInputs();
			}
			// Если рисуем на кривом мониторе, то залить чёрным выступающие края
			FillBorders();
		}
		else if (global_state.game_state == 1001)
		{
		// =====================================================
		// Пауза или гамовер
		// =====================================================
			// Пауза
			if (!global_state.time_processed)
				ResetInputs();
			if (global_state.game_paused)
			{
				if (global_state.time_paused == 0)
				{
					// начальные действия
					// Сыграть звук паузы
					smanager.PlaySound("game_paused");
					// Положение меню паузы
					menu_selection = 0;
					next_menu_selection = 0;
					// Признак, выбран ли пункт меню, который потребует вопроса "да/нет"
					menu_selected = 0;
				}
				global_state.time_paused += time_delta_ms;
				// Убрать паузу по нажатию кнопки
				if (keys_cancel || keys_bomb)
				{
					if (menu_selected)
					{
						menu_selected = 0;
						menu_selection = next_menu_selection;
						ResetInputs();
					}
					else
					{
						// Возврат к игре
						global_state.game_paused = 0;
						global_state.game_state = global_state.next_state;
						smanager.PlaySound("game_paused");
						ResetInputs();
					}
				}
				// Движение по пунктам меню паузы и выбор их
				if (keys_fire)
				{
					keys_fire = 0;
					if (menu_selected)
					{
						if (menu_selection)
						{
							menu_selected = 0;
							menu_selection = next_menu_selection;
						}
						else
						{
							if (next_menu_selection == 1)
							{
								// Выход в титульный экран
								UnloadLevel();
								menu_selection = 0;
								menu_selected = 0;
								global_state.game_state = 5;
								global_state.next_state = 5;
								global_state.time_to_work = 300;
								global_state.time_processed = 0;
								menu_after_splash = 0;
								menu_screen->set_alpha(1.0);
								ResetInputs();
							}
							else
							{
								// Перезапуск уровня
								global_state.game_paused = 0;
								global_state.game_state = global_state.next_state;
								global_state.time_processed = 0;
								SetStartParameters();
								ResetInputs();
							}
						}
					}
					else
					{
						if (menu_selection == 0)
						{
							// Возврат в игру
							global_state.game_paused = 0;
							global_state.game_state = global_state.next_state;
							smanager.PlaySound("game_paused");
							ResetInputs();
						}
						if (menu_selection == 1)
						{
							// Выход в титульный экран
							// да/нет?
							menu_selected = 1;
							menu_selection = 0;
						}
						if (menu_selection == 2)
						{
							// Перезапуск уровня
							// да/нет?
							menu_selected = 1;
							menu_selection = 0;
						}
					}
				}
				if (menu_selected)
				{
					if (keys_right || keys_left)
					{
						keys_right = 0;
						keys_left = 0;
						if (menu_selection)
							menu_selection = 0;
						else
							menu_selection = 1;
					}
				}
				else
				{
					if (keys_up)
					{
						keys_up = 0;
						menu_selection--;
						if (menu_selection < 0)
							menu_selection = 2;
						next_menu_selection = menu_selection;
					}
					if (keys_down)
					{
						keys_down = 0;
						menu_selection++;
						if (menu_selection > 2)
							menu_selection = 0;
						next_menu_selection = menu_selection;
					}
				}
				ResetInputs();
				// Отрисовать сохранёную текстуру
				gc.clear();
				CL_BlendMode pause_blend;
				pause_blend.enable_blending(false);
				gc.set_blend_mode(pause_blend);
				gc.set_texture(0, copy_texture1);
				CL_Draw::texture(gc, CL_Rectf(0, 0, global_state.render_size.width, global_state.render_size.height));
				gc.reset_texture(0);
				gc.reset_blend_mode();
				// И надписи паузы
				if (menu_selected || global_state.game_state == 5)
				{
					CL_String pstring;
					if (next_menu_selection == 1)
						pstring = "Really exit?";
					else
						pstring = "Really restart?";
					sys_font.draw_text(gc, (int)global_state.render_field.get_center().x - sys_font.get_text_size(gc, pstring).width/2, (int)global_state.render_field.get_center().y, pstring, CL_Colorf::white);
					pstring = "Yes";
					CL_Colorf p_col = (menu_selection == 0) ? CL_Colorf::white : CL_Colorf::gray;
					sys_font.draw_text(gc, (int)global_state.render_field.get_center().x - sys_font.get_text_size(gc, pstring).width/2 - 30, (int)global_state.render_field.get_center().y + 30, pstring, p_col);
					pstring = "No";
					p_col = (menu_selection == 1) ? CL_Colorf::white : CL_Colorf::gray;
					sys_font.draw_text(gc, (int)global_state.render_field.get_center().x - sys_font.get_text_size(gc, pstring).width/2 + 30, (int)global_state.render_field.get_center().y + 30, pstring, p_col);
				}
				else
				{
					CL_String pstring("GAME PAUSED");
					sys_font.draw_text(gc, (int)global_state.render_field.get_center().x - sys_font.get_text_size(gc, pstring).width/2, (int)global_state.render_field.get_center().y, pstring, CL_Colorf::white);
					pstring = "Continue";
					CL_Colorf p_col = (menu_selection == 0) ? CL_Colorf::white : CL_Colorf::gray;
					sys_font.draw_text(gc, (int)global_state.render_field.get_center().x - sys_font.get_text_size(gc, pstring).width/2, (int)global_state.render_field.get_center().y + 30, pstring, p_col);
					pstring = "Title";
					p_col = (menu_selection == 1) ? CL_Colorf::white : CL_Colorf::gray;
					sys_font.draw_text(gc, (int)global_state.render_field.get_center().x - sys_font.get_text_size(gc, pstring).width/2, (int)global_state.render_field.get_center().y + 60, pstring, p_col);
					pstring = "Restart";
					p_col = (menu_selection == 2) ? CL_Colorf::white : CL_Colorf::gray;
					sys_font.draw_text(gc, (int)global_state.render_field.get_center().x - sys_font.get_text_size(gc, pstring).width/2, (int)global_state.render_field.get_center().y + 90, pstring, p_col);
				}
			}
			// Гамовер
			if (global_state.game_over)
			{
				UnloadLevel();
				menu_selection = 0;
				global_state.game_state = 5;
				ResetInputs();
			}
			// Если рисуем на кривом мониторе, то залить чёрным выступающие края
			FillBorders();
		}
		else if (global_state.game_state == 1500)
		{
		// =====================================================
		// Экран статистики
		// =====================================================
			if (global_state.time_paused == 0)
			{
				// Начальные действия
				// Произвести непосредственно подсчёт статистики
				global_state.current_level_score = player.score;
				player.score += player.points * 10000 + player.points * player.graze * 500 + ((float)global_state.bullets_blowed / (float)global_state.bullets_launched) * 5000000;
				if (player.score > global_state.hi_score)
				{
					global_state.hi_score = player.score;
					SaveConfig();
				}
			}
			global_state.time_paused += time_delta_ms;
			// Продолжить игру по нажатию кнопок
			if (keys_cancel || keys_bomb || keys_fire)
			{
				// пока выход в меню
				UnloadLevel();
				menu_selection = 0;
				global_state.game_state = 5;
				ResetInputs();
			}
			// Отрисовать экран статистики
			//gc.clear();
			//CL_BlendMode pause_blend;
			//pause_blend.enable_blending(false);
			//gc.set_blend_mode(pause_blend);
			//gc.set_texture(0, copy_texture1);
			//CL_Draw::texture(gc, CL_Rectf(0, 0, global_state.render_size.width, global_state.render_size.height));
			//gc.reset_texture(0);
			//gc.reset_blend_mode();
			// ==============================================
			background.scroll(time_delta_ms);
			effects.Update(time_delta_ms);
			player.Update(time_delta_ms);
			gc.clear();
			game_screen->draw(gc, 0, 0);
			global_state.bg_rect = global_state.clip_rect;
			background.draw(gc);
			player.RenderBack(gc, magic_rings);
			player.Render(gc);
			effects.Render(gc, (CL_Rect) global_state.clip_rect);
			DrawStats(score_font);
			if (global_state.game_dialog)
			{
				dialogs.RenderDialog(gc);
			}
			// =================================================
			// И надписи статистики
			CL_Colorf reccol(0.0f, 0.0f, 0.0f, 0.3f);
			CL_Draw::fill(gc, 48.0f, 50.0f, 400.0f, 430.0f, reccol);
			CL_String sstring = "Points         :";
			sys_font.draw_text(gc, 70.0f, 100.0f, sstring, CL_Colorf::white);
			sstring = "Graze * Points :";
			sys_font.draw_text(gc, 70.0f, 120.0f, sstring, CL_Colorf::white);
			sstring = "Bullets blown  :";
			sys_font.draw_text(gc, 70.0f, 140.0f, sstring, CL_Colorf::white);
			sstring = "+";
			sys_font.draw_text(gc, 270.0f, 160.0f, sstring, CL_Colorf::white);
			sstring = "Stage score    :";
			sys_font.draw_text(gc, 70.0f, 180.0f, sstring, CL_Colorf::white);
			sstring = "Total score    :";
			sys_font.draw_text(gc, 70.0f, 220.0f, sstring, CL_Colorf::white);
			// ===
			sstring = cl_format("%1", player.points * 10000);
			sys_font.draw_text(gc, 280.0f, 100.0f, sstring, CL_Colorf::white);
			sstring = cl_format("%1", player.points * player.graze * 500);
			sys_font.draw_text(gc, 280.0f, 120.0f, sstring, CL_Colorf::white);
			sstring = cl_format("%1", (int)(((float)global_state.bullets_blowed / (float)global_state.bullets_launched) * 5000000));
			sys_font.draw_text(gc, 280.0f, 140.0f, sstring, CL_Colorf::white);
			sstring = cl_format("%1", global_state.current_level_score);
			sys_font.draw_text(gc, 280.0f, 180.0f, sstring, CL_Colorf::white);
			sstring = cl_format("%1", player.score);
			sys_font.draw_text(gc, 280.0f, 220.0f, sstring, CL_Colorf::white);
			// =================================================
			// Если рисуем на кривом мониторе, то залить чёрным выступающие края
			FillBorders();
		}
		else if (global_state.game_state == 2000)
		{
		// =====================================================
			// Финальный фильм и титры
			if (!global_state.time_processed)
			{
				// Загрузка фильмы
				ending.Load(gc, resources, "jingo");
				ResetInputs();
				ending.Start();
			}
			global_state.time_processed += time_delta_ms;
			ending.Update();
			// Рисуем фон
			//gc.clear(CL_Colorf::gray80);
			gc.set_texture(0, ending_back_tex);
			ending_back_tex.set_wrap_mode(cl_wrap_repeat, cl_wrap_repeat, cl_wrap_repeat);
			CL_Draw::texture(gc, CL_Rectf(global_state.render_size));
			// Кадр видео с субтитрами и кредитами
			ending.draw(gc, 100, 100);
			// Если рисуем на кривом мониторе, то залить чёрным выступающие края
			FillBorders();
		}
		// =====================================================

		// Версия
		if (global_state.game_state < 100)
			ShowVersion(small_font);

		// После всего выводим фпс
		fps_counter.show_fps(gc, small_font);

		// И берём скриншот, если надо
		if (keys_screenshot)
		{
			Screenshot();
			keys_screenshot = 0;
		}

		// закончили цикл
		window.flip(1);

		CL_KeepAlive::process(0);

		current_time = CL_System::get_time();
		const int main_loop_rate = 16;	// 16 ms (60 hz)
		int time_to_sleep_for = main_loop_rate - (current_time - last_time);
		fps_counter.frame_shown();
		if (time_to_sleep_for > 0)
			CL_System::sleep(time_to_sleep_for);
	}
	SaveConfig();
	return 0;
}

void Application::UnloadLevel()
{
	global_state.time_processed = 0;
	background.unload();
	boss_background.unload();
	patterns.Clear();
	bmanager.Clear();
	emanager.Clear();
	effects.Clear();
	bonus_manager.Clear();
}

void Application::on_window_close()
{
	quit = true;
}

void Application::on_window_resize(int width, int height)
{
	new_size.width = width;
	new_size.height = height;
	keys_resize_event++;
}

void Application::on_input_up(const CL_InputEvent &key, const CL_InputState &state)
{
	if((key.id == CL_KEY_F4) && key.alt)
	{
		quit = true;
	}
}

void Application::on_input_down(const CL_InputEvent &key, const CL_InputState &state)
{
	// Переключение на полноэкранный режим
	if(key.id == CL_KEY_F11)
	{
		keys_fullscreen++;
	}
	// Скриншот
	if(key.id == CL_KEY_HOME)
	{
		keys_screenshot++;
	}
	// Добавляем нажатые клавиши на нужных экранах
	// === TO DO - определение клавиш в соответствии с конфигурацией
	switch (global_state.game_state)
	{
	case 2:
		// Выбор языка
		if(key.id == CL_KEY_Z || key.id == CL_KEY_RETURN)
		{
			keys_fire++;
		}
		if(key.id == CL_KEY_UP)
		{
			keys_up++;
		}
		if(key.id == CL_KEY_DOWN)
		{
			keys_down++;
		}
		break;
	case 5:
		// Главное меню
		if(key.id == CL_KEY_Z || key.id == CL_KEY_RETURN)
		{
			keys_fire++;
		}
		if(key.id == CL_KEY_UP)
		{
			keys_up++;
		}
		if(key.id == CL_KEY_DOWN)
		{
			keys_down++;
		}
		if(key.id == CL_KEY_ESCAPE || key.id == CL_KEY_X)
		{
			keys_cancel++;
		}
		break;
	case 7:
	case 9:
		// Меню опций и настроек кнопок
		if(key.id == CL_KEY_Z || key.id == CL_KEY_RETURN)
		{
			keys_fire++;
		}
		if(key.id == CL_KEY_UP)
		{
			keys_up++;
		}
		if(key.id == CL_KEY_DOWN)
		{
			keys_down++;
		}
		if(key.id == CL_KEY_RIGHT)
		{
			keys_right++;
		}
		if(key.id == CL_KEY_LEFT)
		{
			keys_left++;
		}
		if(key.id == CL_KEY_ESCAPE || key.id == CL_KEY_X)
		{
			keys_cancel++;
		}
		break;
	case 100:
	case 200:
	case 300:
		// Процесс игры
		if(key.id == CL_KEY_Z || key.id == CL_KEY_RETURN)
		{
			keys_fire++;
		}
		if(key.id == CL_KEY_ESCAPE)
		{
			keys_cancel++;
		}
		break;
	case 1001:
		// Меню паузы
		if(key.id == CL_KEY_Z || key.id == CL_KEY_RETURN)
		{
			keys_fire++;
		}
		if(key.id == CL_KEY_UP)
		{
			keys_up++;
		}
		if(key.id == CL_KEY_DOWN)
		{
			keys_down++;
		}
		if(key.id == CL_KEY_RIGHT)
		{
			keys_right++;
		}
		if(key.id == CL_KEY_LEFT)
		{
			keys_left++;
		}
		if(key.id == CL_KEY_ESCAPE)
		{
			keys_cancel++;
		}
		if(key.id == CL_KEY_X)
		{
			keys_bomb++;
		}
		break;
	case 1500:
		// Меню статистики
		if(key.id == CL_KEY_Z || key.id == CL_KEY_RETURN)
		{
			keys_fire++;
		}
		if(key.id == CL_KEY_ESCAPE)
		{
			keys_cancel++;
		}
		if(key.id == CL_KEY_X)
		{
			keys_bomb++;
		}
		break;
	default:
		break;
	}
}

void Application::on_joystick_down(const CL_InputEvent &key, const CL_InputState &state)
{
	if (global_state.game_state == 2 || global_state.game_state == 5 || global_state.game_state == 7)
	{
		if(key.id == global_state.key_fire)
		{
			keys_fire++;
		}
		if(key.id == global_state.key_bomb)
		{
			keys_cancel++;
		}
	}
	if (global_state.game_state == 9)
	{
		if(key.id == global_state.key_fire)
		{
			keys_fire++;
		}
		if(key.id == global_state.key_bomb)
		{
			keys_cancel++;
		}
		keys_joy = key.id + 1;
	}
	if (global_state.game_state == 100 || global_state.game_state == 200)
	{
		if(key.id == global_state.key_fire)
		{
			keys_fire++;
		}
		if(key.id == global_state.key_pause)
		{
			keys_cancel++;
		}
	}
	if (global_state.game_state == 1001 || global_state.game_state == 1500)
	{
		if(key.id == global_state.key_pause)
		{
			keys_cancel++;
		}
		if(key.id == global_state.key_fire)
		{
			keys_fire++;
		}
		if(key.id == global_state.key_bomb)
		{
			keys_bomb++;
		}
	}
}

void Application::on_joystick_axis_move(const CL_InputEvent &joy, const CL_InputState &state)
{
	if (global_state.game_state == 2 || global_state.game_state == 5 || global_state.game_state == 7 || global_state.game_state == 9 || global_state.game_state == 1001)
	{
		if (joy.id == 0)
		{
			float timenow = (float)CL_System::get_time();
			bool valid;
			if ((last_joy_time + 200) > timenow)
				valid = false;
			else
				valid = true;
			float axis_x = (float)ic.get_joystick().get_axis(0);
			float axis_y = (float)ic.get_joystick().get_axis(1);
			if (axis_x < -(global_state.axis_sens))
			{
				if ((last_joy_x != -1) && valid)
				{
					keys_left++;
					last_joy_time = timenow;
				}
				last_joy_x = -1;
			}
			else if (axis_x > global_state.axis_sens)
			{
				if ((last_joy_x != -1) && valid)
				{
					keys_right++;
					last_joy_time = timenow;
				}
				last_joy_x = 1;
			}
			else
				last_joy_x = 0;
			if (axis_y < -(global_state.axis_sens))
			{
				if ((last_joy_y != -1) && valid)
				{
					keys_up++;
					last_joy_time = timenow;
				}
				last_joy_y = -1;
			}
			else if (axis_y > global_state.axis_sens)
			{
				if ((last_joy_y != -1) && valid)
				{
					keys_down++;
					last_joy_time = timenow;
				}
				last_joy_y = 1;
			}
			else
				last_joy_y = 0;
		}
		else if(joy.id == 32)
		{
			float dpad = (float)ic.get_joystick().get_axis(32);
			if (dpad != last_pad)
			{
				last_pad = dpad;
				if (dpad == 0)
					keys_up++;
				if (dpad == 9000)
					keys_right++;
				if (dpad == 18000)
					keys_down++;
				if (dpad == 27000)
					keys_left++;
			}
		}
	}
}

void Application::ResetInputs()
{
	keys_up = 0;
	keys_down = 0;
	keys_left = 0;
	keys_right = 0;
	keys_fire = 0;
	keys_cancel = 0;
	keys_aim = 0;
	keys_bomb = 0;
	keys_fullscreen = 0;
	keys_resize_event = 0;
	keys_joy = 0;
	keys_screenshot = 0;
}

void Application::SetStartParameters()
{
	global_state.game_paused = 0;
	global_state.game_dialog = 0;
	global_state.game_over = 0;
	global_state.game_level_end = 0;
	global_state.game_boss_battle = 0;
	global_state.game_boss_spellcard_active = 0;
	player.Reset();
	player.lives = global_state.player_lives - 1; // В игре считаются лишние жизни сверх той, что есть
	player.invicible = player.invicible_time;
	player.wind = 100.0f;
	player.is_bomb = false;
	player.wind_trigger = false;
	player.wind_activated = false;
	player.position = CL_Vec2<float>(255,550);
	player.prev_position = CL_Vec2<float>(255,550);
	// Обнулим все хранилища объектов
}

void Application::ReplaceKey(int before, int after)
{
	if (global_state.key_bomb == before)
		global_state.key_bomb = after;
	else if (global_state.key_fire == before)
		global_state.key_fire = after;
	else if (global_state.key_focus == before)
		global_state.key_focus = after;
	else if (global_state.key_pause == before)
		global_state.key_pause = after;
	else if (global_state.key_skip == before)
		global_state.key_skip = after;
	else if (global_state.key_spell == before)
		global_state.key_spell = after;
}

CL_String Application::get_text_line(CL_String name)
{
	return text_resources.get_resource(name).get_element().get_text();
}

CL_String Application::get_option_string(CL_String name)
{
	CL_DomElement element = resources.get_resource("options").get_element();
	std::vector<CL_DomNode> param_nodes = element.select_nodes("option");
	for (size_t p_index = 0; p_index < param_nodes.size(); p_index++)
		if (param_nodes[p_index].to_element().get_attribute("name") == name)
			return param_nodes[p_index].to_element().get_text();
	return CL_String("");
}

float Application::get_option_float(CL_String name)
{
	CL_DomElement element = resources.get_resource("options").get_element();
	std::vector<CL_DomNode> param_nodes = element.select_nodes("option");
	for (size_t p_index = 0; p_index < param_nodes.size(); p_index++)
		if (param_nodes[p_index].to_element().get_attribute("name") == name)
			return CL_StringHelp::text_to_float(param_nodes[p_index].to_element().get_text());
	return 0;
}

int Application::get_option_int(CL_String name)
{
	CL_DomElement element = resources.get_resource("options").get_element();
	std::vector<CL_DomNode> param_nodes = element.select_nodes("option");
	for (size_t p_index = 0; p_index < param_nodes.size(); p_index++)
		if (param_nodes[p_index].to_element().get_attribute("name") == name)
			return CL_StringHelp::text_to_int(param_nodes[p_index].to_element().get_text());
	return 0;
}

void Application::DrawStats(CL_Font &_font)
{
	game_stats->set_frame(0);
	game_stats->draw(gc, 434, 16);
	game_stats->set_frame(1);
	game_stats->draw(gc, 434, 40);
	game_stats->set_frame(2);
	game_stats->draw(gc, 434, 74);
	game_stats->set_frame(3);
	game_stats->draw(gc, 434, 98);
	game_stats->set_frame(7);
	game_stats->draw(gc, 434, 132);
	game_stats->set_frame(4);
	game_stats->draw(gc, 434, 156);
	game_stats->set_frame(5);
	game_stats->draw(gc, 434, 190);
	game_stats->set_frame(6);
	game_stats->draw(gc, 434, 214);
	if (player.score > global_state.hi_score)
		global_state.hi_score = player.score;
	CL_String hiscore_string(cl_format("%1", global_state.hi_score));
	while (hiscore_string.length() < 10)
		hiscore_string.insert(0, "0");
	CL_String score_string(cl_format("%1", player.score));
	while (score_string.length() < 10)
		score_string.insert(0, "0");
	_font.draw_text(gc, 518, 40, hiscore_string);
	_font.draw_text(gc, 518, 64, score_string);
	// Жизни
	game_stats->set_frame(9);
	for (int t=0; t<player.lives; t++)
		game_stats->draw(gc, 518 + t*25, 74);
	// Бомбы
	game_stats->set_frame(10);
	for (int t=0; t<player.spells; t++)
		game_stats->draw(gc, 518 + t*25, 98);
	// Power
	if (player.power == 128)
	{
		game_stats->set_frame(8);
		game_stats->draw(gc, 518, 132);
	}
	else
	{
		CL_String power_string(cl_format("%1/128", player.power));
		_font.draw_text(gc, 518, 156, power_string);
	}
	// Wind power
	CL_String wind_string(cl_format("%1%", (int)player.wind));
	_font.draw_text(gc, 580, 180, wind_string);

	// Points
	CL_String points_string(cl_format("%1", player.points));
	_font.draw_text(gc, 518, 214, points_string);
	// Graze
	CL_String graze_string(cl_format("%1", player.graze));
	_font.draw_text(gc, 518, 238, graze_string);

	// Линейка времени спеллкарты
	// максимальное время - 30 секунд
	float llen = 120.0f * ((float)player.spell_time / (float)player.spellcard_max_duration);
	CL_Draw::line(gc, 670.0f, 165.0f, 670.0f, 175.0f, CL_Colorf::white);
	CL_Draw::line(gc, 791.0f, 165.0f, 791.0f, 175.0f, CL_Colorf::white);
	CL_Draw::line(gc, 690.0f, 167.0f, 690.0f, 173.0f, CL_Colorf::white);
	CL_Draw::line(gc, 710.0f, 167.0f, 710.0f, 173.0f, CL_Colorf::white);
	CL_Draw::line(gc, 730.0f, 167.0f, 730.0f, 173.0f, CL_Colorf::white);
	CL_Draw::line(gc, 750.0f, 167.0f, 750.0f, 173.0f, CL_Colorf::white);
	CL_Draw::line(gc, 770.0f, 167.0f, 770.0f, 173.0f, CL_Colorf::white);
	if (player.spells > 0)
		CL_Draw::line(gc, 670.0f, 169.0f, 790.0f, 169.0f, CL_Colorf::teal);
	CL_Draw::line(gc, 670.0f, 170.0f, 670.0f + llen, 170.0f, CL_Colorf::aqua);
	CL_Draw::line(gc, 670.0f, 171.0f, 670.0f + llen, 171.0f, CL_Colorf::aqua);
	CL_Draw::line(gc, 670.0f, 169.0f, 670.0f + llen, 169.0f, CL_Colorf::aqua);

	// Линейка жизней и таймер во время активированной спеллкарты
	if (player.spellcard_activated)
	{
		float lifeline = 40.0f + ((float)player.hp / (float)player.base_hp) * 450.0f;
		CL_Draw::line(gc, 40.0f, 560.0f, lifeline, 560.0f, CL_Colorf::gray80);
		CL_Draw::line(gc, 40.0f, 561.0f, lifeline, 561.0f, CL_Colorf::gray80);
		CL_Draw::line(gc, 40.0f, 562.0f, lifeline, 562.0f, CL_Colorf::gray80);
		CL_Draw::line(gc, 40.0f, 563.0f, lifeline, 563.0f, CL_Colorf::gray50);
		CL_String time_string(cl_format("%1", (1 + player.spell_time_remaining / 1000)));
		if (player.spell_time_remaining < 5000)
			_font.draw_text(gc, 495, 570, time_string, CL_Colorf::lightcoral);
		else
			_font.draw_text(gc, 495, 570, time_string, CL_Colorf::gray80);
	}
}

void Application::DrawBossStats(CL_Font &_font)
{
	EnemyBoss* eboss = emanager.GetBoss();
	if (eboss)
	{
		float nonspellHP = (float)eboss->spell_patterns[eboss->current_spellcard].nonspellhp;
		float spellHP = (float)eboss->spell_patterns[eboss->current_spellcard].spellhp;
		int curlvl = eboss->current_spell_level;
		float curhp;
		if (global_state.game_boss_spellcard_active)
		{
			curhp = (float)eboss->spell_hp;
		}
		else
		{
			if (curlvl == 0)
				curhp = nonspellHP;
			else
				curhp = spellHP;
		}
		int sptime = (int)eboss->spell_time / 1000 + 1;
		float bosstime = eboss->time_lived;
		if (curhp < 0)
			curhp = 0;
		float l1, l2, lline;
		if (bosstime > 1700.0f) // время развёртывания полосы жизней босса
			lline = 340.0f;
		else
			lline = 340.0f * (bosstime / 1700.0f);
		// масштаб спелла к нонспеллу 1:10
		if (curlvl == 0)
		{
			// nonspell
			l1 = lline * ((spellHP / 10.0f) / ((spellHP / 10.0f) + nonspellHP));
			l2 = lline * (curhp / ((spellHP / 10.0f) + nonspellHP));
		}
		else
		{
			// spell
			l1 = lline * ((curhp / 10.0f) / ((spellHP / 10.0f) + nonspellHP));
			l2 = 0;
		}
		CL_Draw::line(gc, 40.0f, 25.0f, 40.0f + l1, 25.0f, CL_Colorf::lightcoral);
		CL_Draw::line(gc, 40.0f, 26.0f, 40.0f + l1, 26.0f, CL_Colorf::lightcoral);
		CL_Draw::line(gc, 40.0f, 27.0f, 40.0f + l1, 27.0f, CL_Colorf::lightcoral);
		CL_Draw::line(gc, 40.0f, 28.0f, 40.0f + l1, 28.0f, CL_Colorf::salmon);
		if (curlvl == 0)
		{
			CL_Draw::line(gc, 40.0f + l1, 25.0f, 40.0f + l1 + l2, 25.0f, CL_Colorf::gray80);
			CL_Draw::line(gc, 40.0f + l1, 26.0f, 40.0f + l1 + l2, 26.0f, CL_Colorf::gray80);
			CL_Draw::line(gc, 40.0f + l1, 27.0f, 40.0f + l1 + l2, 27.0f, CL_Colorf::gray80);
			CL_Draw::line(gc, 40.0f + l1, 28.0f, 40.0f + l1 + l2, 28.0f, CL_Colorf::gray50);
		}
		if (global_state.game_boss_spellcard_active)
		{
			// Таймер
			CL_String time_string(cl_format("%1", sptime));
			if (sptime < 6)
				_font.draw_text(gc, 385, 40, time_string, CL_Colorf::lightcoral);
			else
				_font.draw_text(gc, 385, 40, time_string, CL_Colorf::gray80);
			// Название спеллкарты
			eboss->spellcard_name_effect.Render(gc);
		}
	}
}

void Application::DrawBossBackground(float time)
{
	// Фон спеллкарты, если задействован
	boss_background.scroll(time);
	boss_background.draw(gc);

	// Круги и пентаграммы босса
	EnemyBoss* boss = emanager.GetBoss();
	boss->RenderBack(gc, time); // рисует пентаграммы и просчитывает круги
	// рисуем круги
	gc.set_cliprect(global_state.clip_rect);
	for (int i=0; i < boss->rnd_rings; i++)
	{
		CL_Colorf c(1.0f, 1.0f, 1.0f, boss->rnd_ring_alpha[i]);
		magic_rings->set_frame(boss->rnd_ring_index[i]);
		magic_rings->draw_ring(gc, boss->rnd_rings_center.x, boss->rnd_rings_center.y, boss->rnd_ring_radius[i], boss->rnd_ring_width[i], boss->rnd_ring_position[i], c);
	}
	gc.pop_cliprect();
}

void Application::ShowVersion(CL_Font &_font)
{
	int ver1 = global_state.version / 1000000;
	int ver2 = global_state.version % 1000000;
	CL_String ver_str = CL_String("Version ") + CL_StringHelp::int_to_text(ver1) + CL_String(".") + CL_StringHelp::int_to_text(ver2);
	_font.draw_text(gc, 10, 479, ver_str);
}

void Application::FillBorders()
{
	// Если рисуем на кривом мониторе, то залить чёрным выступающие края
	if (global_state.translate.x != 0)
	{
		CL_Draw::fill(gc, 0, 0, -((float)global_state.translate.x + 1.0f), (float)global_state.screen_size.height, CL_Colorf::black);
		CL_Draw::fill(gc, global_state.render_size.width, 0, (float)global_state.screen_size.width, (float)global_state.screen_size.height, CL_Colorf::black);
	}
	if (global_state.translate.y != 0)
	{
		CL_Draw::fill(gc, 0, 0, (float)global_state.screen_size.width, -((float)global_state.translate.y + 1), CL_Colorf::black);
		CL_Draw::fill(gc, 0, global_state.render_size.height, (float)global_state.screen_size.width,  (float)global_state.screen_size.height, CL_Colorf::black);
	}
}

// Переопределить размеры окна после растягивания пользователем
void Application::_ResizeWindow(CL_DisplayWindow &win)
{
	if (new_size.width < 800 || new_size.height < 600)
		new_size = (CL_Size)global_state.render_size;
	global_state.screen_size = new_size;
	if (((float)global_state.screen_size.height / (float)global_state.screen_size.width) != (3.0f / 4.0f))
	{
		if ((global_state.render_size.height / global_state.render_size.width) > ((float)global_state.screen_size.height / (float)global_state.screen_size.width))
		{
			global_state.screen_size.width = global_state.screen_size.height * 4 / 3;
		}
		else
		{
			global_state.screen_size.height = global_state.screen_size.width * 3 / 4;
		}
	}
	global_state.window_size = global_state.screen_size;
	global_state.scale = (float)global_state.screen_size.width / global_state.render_size.width;
	global_state.clip_rect = CL_Rectf(global_state.render_field.left * global_state.scale, global_state.render_field.top * global_state.scale, global_state.render_field.right * global_state.scale, global_state.render_field.bottom * global_state.scale);
	win.set_size(global_state.screen_size.width, global_state.screen_size.height, true);
	keys_resize_event = 0;
	gc.set_translate(global_state.translate.x, global_state.translate.y);
	gc.push_scale(global_state.scale, global_state.scale);
	SaveConfig();
}

// Переключиться между полноэкранным/оконным режимом
void Application::_RecreateWindow(CL_DisplayWindow &win)
{
	if (global_state.fullscreen)
	{
		global_state.window_size = global_state.screen_size;
		win_desc.set_fullscreen(true);
		win_desc.set_decorations(false);
		win_desc.set_allow_resize(false);
	}
	else
	{
		global_state.screen_size = global_state.window_size;
		win_desc.set_fullscreen(false);
		win_desc.set_decorations(true);
		win_desc.set_size(global_state.screen_size, true);
		win_desc.set_allow_resize(true);
	}
	// Уничтожаем фреймбуфер
	if (!framebuffer1.is_null())
		framebuffer1.detach_color_buffer(0, copy_texture1);
	framebuffer1 = CL_FrameBuffer();
	// И пересоздаём
	CL_DisplayWindow new_window(win_desc);
	//gc = new_window.get_gc();
	ic = new_window.get_ic();

	win = new_window;

	// Переподключить ввод пользователя и все слоты
	ic = win.get_ic();

	player.AttachInput(win);

	slot_quit = win.sig_window_close().connect(this, &Application::on_window_close);
	slot_win_resize = win.sig_resize().connect(this, &Application::on_window_resize);
	slot_input_up = (win.get_ic().get_keyboard()).sig_key_up().connect(this, &Application::on_input_up);
	slot_input_down = (win.get_ic().get_keyboard()).sig_key_down().connect(this, &Application::on_input_down);
	if (win.get_ic().get_joystick_count())
	{
		slot_axis_move = (win.get_ic().get_joystick()).sig_axis_move().connect(this, &Application::on_joystick_axis_move);
		slot_joy_down = (win.get_ic().get_joystick()).sig_key_down().connect(this, &Application::on_joystick_down);
	}

	// Переподключить gc
	_ReconnectGC(win);

	framebuffer1 = CL_FrameBuffer(gc);
	framebuffer1.attach_color_buffer(0, copy_texture1);

	cl_log_event("Debug", "Scale = %1, screen size: %2, %3", global_state.scale, global_state.screen_size.width, global_state.screen_size.height);

	if (global_state.fullscreen)
		win.hide_cursor();
	else
		win.show_cursor();
	SaveConfig();
}

// Переподключение gc на нужное окно
void Application::_ReconnectGC(CL_DisplayWindow &win)
{
	gc = win.get_gc();
	// не делать лишнюю работу для скрытого окна
	if (!win.is_visible())
		return;

	// Растягивание и сдвиг области вывода
	global_state.screen_size = gc.get_size();
	if (global_state.fullscreen)
	{
		if ((global_state.render_size.height / global_state.render_size.width) > ((float)global_state.screen_size.height / (float)global_state.screen_size.width))
		{
			global_state.scale = (float)global_state.screen_size.height / global_state.render_size.height;
			global_state.translate.x = ((float)global_state.screen_size.width - (global_state.render_size.width * global_state.scale)) / 2;
			global_state.translate.y = 0;
		}
		else
		{
			global_state.scale = (float)global_state.screen_size.width / global_state.render_size.width;
			global_state.translate.x = 0;
			global_state.translate.y = ((float)global_state.screen_size.height - (global_state.render_size.height * global_state.scale)) / 2;
		}
	}
	else
	{
		global_state.scale = (float)global_state.screen_size.width / global_state.render_size.width;
		global_state.translate.x = 0;
		global_state.translate.y = 0;
	}
	global_state.clip_rect = CL_Rectf(global_state.render_field.left * global_state.scale, global_state.render_field.top * global_state.scale, global_state.render_field.right * global_state.scale, global_state.render_field.bottom * global_state.scale);
	global_state.clip_rect.translate(global_state.translate);
	gc.set_translate(global_state.translate.x, global_state.translate.y);
	gc.push_scale(global_state.scale, global_state.scale);
}

// Сохранить конфигурацию в файл настроек
void Application::SaveConfig()
{
	CL_File file("config.dat", CL_File::open_always, CL_File::access_write);
	file.write_int32(global_state.version);
	file.write_int8(global_state.fullscreen);
	file.write_int32(global_state.window_size.width);
	file.write_int32(global_state.window_size.height);
	file.write_uint32(global_state.hi_score);
	file.write_int8(global_state.player_lives);
	file.write_int8(global_state.music_on);
	file.write_int8(global_state.sfx_volume);
	file.write_int8(global_state.music_volume);
	file.write_float(global_state.axis_sens);
	file.write_int8(global_state.key_fire);
	file.write_int8(global_state.key_bomb);
	file.write_int8(global_state.key_focus);
	file.write_int8(global_state.key_spell);
	file.write_int8(global_state.key_pause);
	file.write_int8(global_state.key_skip);
	file.write_int8(global_state.shotslow);
	file.write_int8(global_state.lang);
	file.close();

	global_state.sfx_vol = (float)global_state.sfx_volume / 100;
	global_state.music_vol = (float)global_state.music_volume / 100;
}

// Загрузить конфигурацию из файла настроек
void Application::LoadConfig()
{
	if (ConfigExists())
	{
		CL_File file("config.dat", CL_File::open_existing, CL_File::access_read);
		int vers = file.read_int32();
		global_state.fullscreen = !(!file.read_int8());
		global_state.window_size.width = file.read_int32();
		global_state.window_size.height = file.read_int32();
		global_state.hi_score = file.read_uint32();
		global_state.player_lives = file.read_int8();
		global_state.music_on = !(!file.read_int8());
		global_state.sfx_volume = file.read_int8();
		global_state.music_volume = file.read_int8();
		global_state.axis_sens = file.read_float();
		global_state.key_fire = file.read_int8();
		global_state.key_bomb = file.read_int8();
		global_state.key_focus = file.read_int8();
		global_state.key_spell = file.read_int8();
		global_state.key_pause = file.read_int8();
		global_state.key_skip = file.read_int8();
		global_state.shotslow = file.read_int8();
		global_state.lang = file.read_int8();
		file.close();

		global_state.sfx_vol = (float)global_state.sfx_volume / 100;
		global_state.music_vol = (float)global_state.music_volume / 100;

		global_state.player_continues = 3;
	}
}

// Если файла конфигурации нет, создать новый с дефолтными значениями
void Application::CreateNewConfig()
{
	global_state.fullscreen = false;
	global_state.screen_size = (CL_Size)global_state.render_size;
	global_state.window_size = (CL_Size)global_state.render_size;
	global_state.hi_score = 9999;
	global_state.player_lives = 3;
	global_state.player_continues = 3;
	global_state.music_on = true;
	global_state.sfx_volume = 80;
	global_state.music_volume = 90;
	global_state.axis_sens = 0.5;
	global_state.key_fire = 1;
	global_state.key_bomb = 0;
	global_state.key_focus = 5;
	global_state.key_spell = 3;
	global_state.key_pause = 7;
	global_state.key_skip = 2;
	global_state.shotslow = 0;
	global_state.lang = 0;
	global_state.is_extra_available = 0;
	SaveConfig();

	global_state.sfx_vol = (float)global_state.sfx_volume / 100;
	global_state.music_vol = (float)global_state.music_volume / 100;
}

bool Application::ConfigExists()
{
	if (CL_FileHelp::file_exists("config.dat"))
	{
		CL_File file("config.dat", CL_File::open_existing, CL_File::access_read);
		int size = file.get_size();
		int vers = file.read_int32();
		file.close();
		return ((size == 33) && (vers == global_state.version));
	}
	else
		return false;
}

void Application::Screenshot()
{
	CL_DirectoryScanner ds;
	if (!ds.scan(CL_Directory::get_current() + "\\screenshot\\"))
	{
		CL_Directory::create("screenshot");
		if (!ds.scan(CL_Directory::get_current() + "\\screenshot\\"))
		{
			cl_log_event("Debug", "Failed to save screenshot");
			return;
		}
	}
	int nn = 1;
	do
	{
		//cl_log_event("Debug", "File in dir : %1", ds.get_name());
		CL_String fn = ds.get_name();
		if (fn.substr(0, 5) == "ayaya")
		{
			int n2 = CL_StringHelp::text_to_int(fn.substr(6, 6));
			if (n2 >= nn)
				nn = n2 + 1;
		}
	} while (ds.next());
	CL_String fname("screenshot\\ayaya");
	fname += get_zeroed_int(nn, 6);
	fname += CL_String(".png");
	CL_PixelBuffer sbuf = gc.get_pixeldata();
	CL_PNGProvider::save(sbuf.to_format(cl_rgb8), fname);
	cl_log_event("Debug", "Screenshot saved");
}

CL_String Application::get_zeroed_int(int n, int zeros)
{
	CL_String res = CL_StringHelp::int_to_text(n);
	while (res.length() < zeros)
		res = CL_String("0") + res;
	return res;
}

void Application::CheckTimeStart()
{
	performance_time_check = (float)CL_System::get_time();
}

void Application::CheckTime(CL_String mark)
{
	float new_time = (float)CL_System::get_time();
	if (new_time - performance_time_check > 20.0f)
		cl_log_event("Performance", "Pervormance drop of %1 at %2", new_time - performance_time_check, mark);
	performance_time_check = new_time;
}
